diff --git a/.gitignore b/.gitignore index 407b72c3e8..05e8466434 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,17 @@ sdl # Compiled dll openrct2.dll +# Distribution +distribution/windows/*.exe + # Build artifacts .cache +#libcurl +lib/libcurl/ +#libjansson +lib/jansson/ + ################# ## Eclipse ################# @@ -227,3 +235,5 @@ pip-log.txt #IDA files openrct2.id* openrct2.nam +openrct2.til +data/g2.dat diff --git a/CMakeLists.txt b/CMakeLists.txt index 32be94c0cc..2f830b4805 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,14 @@ project(${PROJECT}) add_definitions(-DORCT2_RESOURCE_DIR="${ORCT2_RESOURCE_DIR}") add_definitions(-DHAVE_CONFIG_H) +add_definitions(-DCURL_STATICLIB) +#uncomment the line bellow if you don't want to build openrct2 with twitch integration +#add_definitions(-DDISABLE_HTTP -DDISABLE_TWITCH) + +set(ORCALIBS_INCLUDE /usr/local/cross-tools/orcalibs/include) +set(JANSSON_INCLUDE /usr/local/cross-tools/orcalibs/include/jansson) +set(ORCALIBS_LIB_DIR /usr/local/cross-tools/orcalibs/lib) +set(ORCALIBS_LIB jansson curl ssl crypto ws2_32) # include lib include_directories("lib/") @@ -44,7 +52,8 @@ if (UNIX) INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS}) endif (UNIX) -LINK_DIRECTORIES(${SDL2_LIBRARY_DIRS}) +INCLUDE_DIRECTORIES(${ORCALIBS_INCLUDE} ${JANSSON_INCLUDE}) +LINK_DIRECTORIES(${SDL2_LIBRARY_DIRS} ${ORCALIBS_LIB_DIR}) # build as library for now, replace with add_executable add_library(${PROJECT} SHARED ${ORCT2_SOURCES}) @@ -55,7 +64,7 @@ add_library(${PROJECT} SHARED ${ORCT2_SOURCES}) # libopenrct2.dll -> openrct2.dll set_target_properties(${PROJECT} PROPERTIES PREFIX "") -TARGET_LINK_LIBRARIES(${PROJECT} ${SDL2_LIBRARIES}) +TARGET_LINK_LIBRARIES(${PROJECT} ${SDL2_LIBRARIES} ${ORCALIBS_LIB}) if (WIN32) target_link_libraries(${PROJECT} winmm.lib -limm32 -lversion -ldsound) diff --git a/CMakeLists_mingw.txt b/CMakeLists_mingw.txt index 9a333ac9cf..96fae66e68 100644 --- a/CMakeLists_mingw.txt +++ b/CMakeLists_mingw.txt @@ -10,7 +10,8 @@ SET(PKG_CONFIG_EXECUTABLE ${COMPILER_PREFIX}-pkg-config) # potential flags to make code more similar to MSVC: # -fshort-wchar -fshort-enums -mms-bitfields # -set(CMAKE_C_FLAGS "-masm=intel -std=gnu99 -fpack-struct=2" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS "-masm=intel -std=gnu99 -fpack-struct=1" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS "-masm=intel -std=c++0x -std=gnu++0x -fpack-struct=1" CACHE STRING "" FORCE) set(CMAKE_SHARED_LINKER_FLAGS "-static-libgcc -static-libstdc++" CACHE STRING "" FORCE) # find and include SDL2 @@ -19,7 +20,7 @@ PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS}) if(APPLE) - SET(TARGET_ENVIRONMENT /usr/local/mingw-w32-bin_i686-darwin/i686-w64-mingw32) + SET(TARGET_ENVIRONMENT /usr/local/mingw-w32-bin_i686-darwin/i686-w64-mingw32) else() SET(TARGET_ENVIRONMENT /usr/i686-w64-mingw32) endif(APPLE) diff --git a/build.bat b/build.bat index 8864853060..c60e247902 100644 --- a/build.bat +++ b/build.bat @@ -1 +1 @@ -msbuild .\projects\openrct2.vcxproj /p:Configuration=Release /p:Platform=x86 \ No newline at end of file +msbuild .\projects\openrct2.sln /p:Configuration=Release /p:Platform=Win32 \ No newline at end of file diff --git a/build.sh b/build.sh index b69543ebd8..49df49f378 100755 --- a/build.sh +++ b/build.sh @@ -11,6 +11,11 @@ pushd build make popd +if [[ -z "$DISABLE_G2_BUILD" ]]; then + echo Building: data/g2.dat + ./build_g2.sh > /dev/null 2>&1 +fi + if [[ ! -h openrct2.dll ]]; then ln -s build/openrct2.dll openrct2.dll fi diff --git a/build_g2.bat b/build_g2.bat new file mode 100644 index 0000000000..c2bf10d049 --- /dev/null +++ b/build_g2.bat @@ -0,0 +1 @@ +.\build\release\openrct2.exe sprite build "data\g2.dat" "resources\g2" \ No newline at end of file diff --git a/build_g2.sh b/build_g2.sh new file mode 100755 index 0000000000..d870c40205 --- /dev/null +++ b/build_g2.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +wine openrct2.exe sprite build data/g2.dat resources/g2/ diff --git a/clean.sh b/clean.sh index 03b524eee0..85a5dac6d8 100755 --- a/clean.sh +++ b/clean.sh @@ -3,8 +3,6 @@ set -ev sudo rm -rf /usr/local/cross-tools/i686-w64-mingw32 -#rm -rf .cache -rm -rf .cache/*.patch -rm -rf .cache/SDL2-2.0.3 -rm -rf .cache/i686-w64-mingw32-pkg-config +sudo rm -rf /usr/local/cross-tools/orcalibs +rm -rf .cache rm -rf build diff --git a/contributors.md b/contributors.md new file mode 100644 index 0000000000..7ef94f24ca --- /dev/null +++ b/contributors.md @@ -0,0 +1,86 @@ +# Contributors to OpenRCT2 +Includes all git commit authors. Aliases are GitHub user names. + +## Project team +* Ted John (IntelOrca) - Owner + +## Long term developers +* Ted John (IntelOrca) +* Duncan Frost (duncanspumpkin) + +## Implementation (RCT2) +* Ted John (IntelOrca) +* Duncan Frost (duncanspumpkin) +* Peter Hill (ZedThree) - String handling, misc. +* (qcz) - Scenery window, misc. +* Matthias Lanzinger (lnz) - Climate, finance, scenario, ride reachability +* (zsilencer) - Audio, misc. +* Adrian Wielgosik (adrian17) - Misc. +* (hexdec) - Misc. +* Dennis Devriendt (ddevrien) - Misc. +* Maciek Baron (MaciekBaron) - Misc. +* Michael Steenbeek (Gymnasiast) - Cheats and misc. features +* (AngeloG) - Scrollbar input, misc. +* (jcdavis) - Misc. +* (marcotc) - Rain drawing, misc. +* (vanderkleij) - Misc. +* Ben Pye (benpye) - Misc. +* (JeroenSack) - Misc. +* (Vijfhoek) - Misc. +* (wolfreak99) - Misc. +* Inseok Lee (dlunch) - Original command line +* Robert Jordan (trigger-death) - New UI features, misc. + +## Additional implementation (OpenRCT2) +* (atmaxinger) - User configuration +* (anyc) - Housecleaning, cross-platform fixes +* Miso Zmiric (mzmiric5) - Misc. +* (DutchRPW) - Housecleaning, initialisation +* Jørn Lomax (jvlomax) - User configuration +* (KingHual) - Housecleaning +* Alexander Overvoorde (Overv) - Misc. +* (eezstreet) - Misc. +* Thomas den Hollander (ThomasdenH) - Misc. + +## Bug fixes +* (halfbro) +* (Myrtle) +* (nean) + +## Toolchain +* (Balletie) - OSX +* Kevin Burke (kevinburke) - OSX, Unix +* Miso Zmiric (mzmiric5) - OSX +* Jarno Veuger (JarnoVgr) - Windows build server +* Ted John (IntelOrca) - Windows + +## Documentation +* (honzi) +* Kevin Burke (kevinburke) +* James Robertson (rd3k) +* Max Boße (MakaHost) +* (MaxBareiss) +* Philip Plarkson (Philpax) +* (RollingStar) + +## Translation +* English (UK) - Ted John (IntelOrca), (Tinytimrob) +* French - (fbourigault) +* German - (atmaxinger), (Yepoleb) +* Dutch - Michael Steenbeek (Gymnasiast), (hostbrute), (mrtnptrs), (xzbobzx) +* Spanish - (mdtrooper) +* Swedish - (Jinxit), (mharrys) + +## Graphics +* OpenRCT2 Logo - xzbobzx + +## RollerCoaster Tycoon 2 credits +Design and programming by Chris Sawyer +Graphics by Simon Foster +Sound and music by Allister Brimble +Additional sounds recorded by David Ellis +Representation by Jacqui Lyons at Mar jacq Ltd. + +Thanks to: Peter James Adcock, Joe Booth, and John Wardley + +Licensed to Infogrames Interactive Inc. diff --git a/curl-ca-bundle.crt b/curl-ca-bundle.crt new file mode 100644 index 0000000000..0364447fbc --- /dev/null +++ b/curl-ca-bundle.crt @@ -0,0 +1,4055 @@ +## +## lib/ca-bundle.crt -- Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Tue May 21 14:27:05 2013 +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## + +# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.87 $ $Date: 2012/12/29 16:32:45 $ + +GTE CyberTrust Global Root +========================== +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG +A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz +MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL +Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 +IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u +sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql +HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID +AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW +M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF +NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +Thawte Server CA +================ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE +AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j +b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV +BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u +c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG +A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl +/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 +1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J +GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ +GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +Thawte Premium Server CA +======================== +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE +AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl +ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU +VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 +aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ +cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh +Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ +qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm +SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf +8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t +UCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +Equifax Secure CA +================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR +fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW +8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE +CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS +spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 +zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB +BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 +70+sB3c4 +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 1 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy +MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE +NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i +o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq +kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4 +RbyhkwS7hp86W0N6w4pl +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 3 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy +MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD +VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS +xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi +up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1 +mPnHfxsb1gYgAlihw6ID +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA +TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah +WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf +Tqj/ZA1k +-----END CERTIFICATE----- + +Verisign Class 1 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgd +k4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIq +WpDBucSmFc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9ZrbWB85a7FkCMM +XErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2uluIncrKTdcu1OofdPvAbT6shkdHvC +lUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68DzFc6PLZ +-----END CERTIFICATE----- + +Verisign Class 2 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h +cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp +Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 +c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h +cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp +Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 +c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjx +nNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRC +wiNPStjwDqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEA +ATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/7aHmZuovCfTK +1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAXrXfMSTWqz9iP0b63GJZHc2pUIjRk +LbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnInjBJ7xUS0rg== +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO +FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 +lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT +1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD +Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 +-----END CERTIFICATE----- + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +ValiCert Class 1 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy +MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi +GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm +DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG +lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX +icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP +Orf1LXLI +-----END CERTIFICATE----- + +ValiCert Class 2 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC +CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf +ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ +SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV +UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 +W9ViH0Pd +-----END CERTIFICATE----- + +RSA Root Certificate 1 +====================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td +3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H +BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs +3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF +V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r +on+jjBXu +-----END CERTIFICATE----- + +Verisign Class 1 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/E +bRrsC+MO8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJ +rKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7PoBMAGrgnoeS+ +Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP26KbqxzcSXKMpHgLZ2x87tNcPVkeB +FQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +q2aN17O6x5q25lXQBfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N +y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 +ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrspSCAaWihT37h +a88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/Pc +D98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE----- + +Verisign Class 2 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29y +azE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ug +b25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 +c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y +aXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6 +tW8UvxDOJxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7 +C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQHgiBVrKtaaNS +0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjNqWm6o+sdDZykIKbBoMXRRkwXbdKs +Zj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0 +JhU8wI1NQ0kdvekhktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf +0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU +sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RIsH/7NiXaldDx +JBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//j +GHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS +tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM +8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW +Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX +Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd +RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG +UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +Entrust.net Secure Server CA +============================ +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg +cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl +ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG +A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi +eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p +dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ +aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 +gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw +ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l +dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw +NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow +HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN +Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 +n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC +AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER +gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B +AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS +o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z +2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX +OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Equifax Secure Global eBusiness CA +================================== +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp +bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds +b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV +PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN +qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn +hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs +MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN +I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY +NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 1 +============================= +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB +LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE +ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz +IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ +1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a +IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk +MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW +Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF +AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 +lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ +KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 2 +============================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE +ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y +MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT +DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn +2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5 +BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx +JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e +uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1 +jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia +78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm +V+GRMOrN +-----END CERTIFICATE----- + +AddTrust Low-Value Services Root +================================ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU +cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO +ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 +54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr +oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 +Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui +GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w +HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw +HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt +ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr +mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj +ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +AddTrust Public Services Root +============================= +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU +cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ +BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l +dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu +nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i +d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG +Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw +HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G +A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G +A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 +JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 +Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H +EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +AddTrust Qualified Certificates Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU +cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx +CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx +64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 +KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o +L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR +wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU +MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE +BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y +azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze +RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB +iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +RSA Security 2048 v3 +==================== +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK +ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy +MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb +BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 +Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb +WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH +KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP ++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E +FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY +v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj +0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj +VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 +nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Global CA 2 +==================== +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw +MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ +NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k +LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA +Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b +HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH +K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 +srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh +ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL +OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC +x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF +H4z1Ir+rzoPz4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +UTN-USER First-Network Applications +=================================== +-----BEGIN CERTIFICATE----- +MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzAp +BgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5 +WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5T +YWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBB +cHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFug +mliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4Cj +DUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXu +Ozr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwi +P8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIE +j3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8w +HQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9j +cmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G +CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y +IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTK +RIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4Qp +xFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAq +DbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE +-----END CERTIFICATE----- + +America Online Root Certification Authority 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG +v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z +DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh +sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP +8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z +o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf +GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF +VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft +3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- + +America Online Root Certification Authority 2 +============================================= +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en +fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 +f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO +qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN +RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 +gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn +6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid +FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 +Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj +B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY +T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p ++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg +JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy +zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO +ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh +1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf +GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff +Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP +cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Certum Root CA +============== +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK +ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla +Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u +by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x +wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL +kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ +89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K +Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P +NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ +GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg +GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ +0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS +qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +Comodo Secure Services root +=========================== +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw +MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi +BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP +9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc +rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC +oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V +p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E +FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj +YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm +aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL +DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw +pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H +RR3B7Hzs/Sk= +-----END CERTIFICATE----- + +Comodo Trusted Services root +============================ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw +MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h +bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw +IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 +3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y +/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 +juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS +ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud +DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp +ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl +cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA +BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l +R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O +9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 1 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQw +NjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H88 +7dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9 +EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl +0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF645 +2F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW1ebZrgUa +HXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZT +iFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE9 +28Jj2VuXZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxV +yhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2nBBhjrZTOqMR +vq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2UvkVrCqIexVmiUefkl98HVrhq4uz2P +qYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9Z +IRlXvVWa +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA +============================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE +ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w +HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh +bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt +vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P +jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca +C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth +vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 +22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV +HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v +dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN +BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR +EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw +MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- + +TDC Internet Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE +ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx +NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu +ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j +xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL +znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc +5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 +otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI +AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM +VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM +MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe +UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G +CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m +gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb +O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU +Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- + +TDC OCES Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJESzEMMAoGA1UE +ChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5 +MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuH +nEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0 +zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvV +iGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBde +dObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO +3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB +5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5k +ay9yZXBvc2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBm +cmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLiBDZXJ0aWZp +Y2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x +LjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEM +MAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm +aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy +MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647 ++RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6 +NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4 +A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYsc +A+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9 +AOoBmbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1 +AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2LqL19iUw== +-----END CERTIFICATE----- + +UTN DATACorp SGC Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ +BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa +MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w +HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy +dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys +raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo +wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA +9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv +33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud +DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 +BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD +LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 +I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx +EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP +DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- + +UTN USERFirst Email Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0 +BgNVBAMTLVVUTi1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05 +OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQx +FzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx +ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJz +dC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIx +B8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8 +om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHG +TPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7Nl +yP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws6wIDAQABo4G5MIG2MAsGA1UdDwQE +AwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNV +HR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll +bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH +AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u7mFVbwQ+zzne +xRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+ +5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarV +NZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZ +w7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= +-----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- + +UTN USERFirst Object Root CA +============================ +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAb +BgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAz +NlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx +HjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2Vy +dHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VR +loTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ +w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vu +lBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7 +RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEAAaOBrzCBrDAL +BgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8 +ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly +c3QtT2JqZWN0LmNybDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw +DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw +NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNO +PmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFE +qmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCG +hU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx +NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp +cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn +MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU +xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH +NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW +DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV +d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud +EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v +cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P +AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh +bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD +VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi +fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD +L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN +UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n +ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 +erfutGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +================================== +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx +NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt +YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg +MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw +ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J +1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O +by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl +6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c +8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ +BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j +aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B +Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj +aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y +ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA +PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y +gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ +PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 +IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes +t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +NetLock Qualified (Class QA) Root +================================= +-----BEGIN CERTIFICATE----- +MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVn +eXpvaSAoQ2xhc3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0 +bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0 +LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0 +dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3DQEJARYP +aW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRV +CacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e +8ia6AFQer7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhb +m+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrqOU+L73Sa58XQ +0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0lmT+1fMptsK6ZmfoIYOcZwvK9UdPM +0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAQYwggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2 +YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh +biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQgZWxla3Ryb25p +a3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFz +YW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwg +YXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kg +ZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczov +L3d3dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2Nr +Lm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0 +aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMg +YXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0 +IGluZm9AbmV0bG9jay5uZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3 +DQEBBQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQMznN +wNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+NFAwLvt/MpqNPfMg +W/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTc +R08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR +5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko +-----END CERTIFICATE----- + +NetLock Notary (Class A) Root +============================= +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI +EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j +ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX +DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH +EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD +VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz +cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM +D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ +z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC +/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 +tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 +4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG +A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC +Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv +bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn +LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 +ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz +IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh +IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu +b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg +Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp +bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 +ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP +ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB +CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr +KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM +8CgHrTwXZoi1/baI +-----END CERTIFICATE----- + +NetLock Business (Class B) Root +=============================== +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg +VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD +VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv +bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg +VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S +o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr +1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ +RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh +dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 +ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv +c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg +YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz +Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA +bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl +IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 +YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj +cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM +43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR +stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +NetLock Express (Class C) Root +============================== +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ +BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j +ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z +W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 +euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw +DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN +RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn +YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB +IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i +aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 +ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y +emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k +IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ +UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg +YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 +xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW +gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj +YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH +AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw +Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg +U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 +LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh +cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT +dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC +AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh +3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm +vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk +fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 +fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ +EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl +1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ +lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro +g14= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +Firmaprofesional Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT +GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp +Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA +ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL +MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT +OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 +ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V +j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH +lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf +3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 +NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww +KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG +AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD +ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq +u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf +wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm +7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG +VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= +-----END CERTIFICATE----- + +Wells Fargo Root CA +=================== +-----BEGIN CERTIFICATE----- +MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl +bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv +MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX +x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 +E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 +OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j +sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj +YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF +BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD +ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv +m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R +OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx +x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 +tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= +-----END CERTIFICATE----- + +Swisscom Root CA 1 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 +MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM +MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF +NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe +AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC +b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn +7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN +cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp +WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 +haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY +MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 +MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn +jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ +MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H +VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl +vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl +OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 +1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq +nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy +x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW +NY6E0F/6MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +DST ACES CA X6 +============== +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT +MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha +MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE +CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI +DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa +pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow +GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy +MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu +Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy +dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU +CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 +5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t +Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs +vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 +oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 1 +============================================== +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP +MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 +acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx +MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg +U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB +TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC +aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX +yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i +Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ +8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 +W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 +sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE +q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY +nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2 +============================================== +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN +MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr +dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe +LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI +x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g +QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr +5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB +AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt +Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ +hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P +9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 +UrbnBEI= +-----END CERTIFICATE----- + +SwissSign Platinum CA - G2 +========================== +-----BEGIN CERTIFICATE----- +MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWduIFBsYXRpbnVtIENBIC0gRzIw +HhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMM +U3dpc3NTaWduIEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu +669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UF +eNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kne +WCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIo +j5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/6 +8++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34T +aNhxKFrYzt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjy +domyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3HBqi7Ri6Cr2D ++m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuWae5ogObnmLo2t/5u7Su9IPhlGdpV +CX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCv +zAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1 +Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3 +NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4 +U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8 +KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl +9x8DYSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1B +aYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyIIoK6q8QNs +OktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSY +Mdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAci +IfNAChs0B0QTwoRqjt8ZWr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +WellsSecure Public Root Certificate Authority +============================================= +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM +F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw +NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl +bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD +VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 +iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 +i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 +bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB +K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB +AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu +cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm +lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB +i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww +GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI +K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 +bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj +qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es +E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ +tylv2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +IGC/A +===== +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD +VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE +Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy +MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI +EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT +STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 +TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW +So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy +HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd +frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ +tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB +egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC +iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK +q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q +MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI +lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF +0mBWWg== +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +================================= +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE +BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl +Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO +/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX +WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z +ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 +bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK +9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm +iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG +Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW +mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW +T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +S-TRUST Authentication and Encryption Root CA 2005 PN +===================================================== +-----BEGIN CERTIFICATE----- +MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE +BhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcpMRIwEAYDVQQHEwlTdHV0dGdh +cnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fzc2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVT +LVRSVVNUIEF1dGhlbnRpY2F0aW9uIGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0w +NTA2MjIwMDAwMDBaFw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFk +ZW4tV3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMgRGV1dHNj +aGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJVU1QgQXV0aGVudGljYXRp +b24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBOMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob +4QSwI7+Vio5bG0F/WsPoTUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXL +g3KSwlOyggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1Xgqf +eN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteFhy+S8dF2g08LOlk3 +KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm7QIDAQABo4GSMIGPMBIGA1UdEwEB +/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJv +bmxpbmUxLTIwNDgtNTAdBgNVHQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAU +D8oeXHngovMpttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD +pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFoLtU96G7m1R08 +P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersFiXOMy6ZNwPv2AtawB6MDwidA +nwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0yh9WUUpY6RsZxlj33mA6ykaqP2vROJAA5Veit +F7nTNCtKqUDMFypVZUF0Qn71wK/Ik63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8b +Hz2eBIPdltkdOpQ= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE +BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL +EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 +MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz +dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT +GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG +d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N +oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc +QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ +PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb +MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG +IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD +VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 +LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A +dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA +4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg +AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA +egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 +Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO +PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv +c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h +cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw +IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT +WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV +MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp +Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal +HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT +nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE +aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK +yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB +S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. +====================================== +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT +AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg +LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w +HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ +U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh +IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN +yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU +2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 +4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP +2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm +8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf +HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa +Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK +5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b +czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g +ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF +BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug +cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf +AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX +EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v +/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 +MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 +3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk +eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f +/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h +RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU +Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 2 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw +MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw +IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 +xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ +Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u +SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G +dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ +KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj +TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP +JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk +vQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 3 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw +MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W +yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo +6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ +uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk +2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE +O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 +yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 +IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal +092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc +5A== +-----END CERTIFICATE----- + +TC TrustCenter Universal CA I +============================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN +MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg +VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw +JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC +qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv +xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw +ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O +gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j +BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG +1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy +vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 +ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a +7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +ComSign CA +========== +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0MRMwEQYDVQQD +EwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTMy +MThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMTCkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNp +Z24xCzAJBgNVBAYTAklMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49q +ROR+WCf4C9DklBKK8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTy +P2Q298CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb2CEJKHxN +GGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxCejVb7Us6eva1jsz/D3zk +YDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7KpiXd3DTKaCQeQzC6zJMw9kglcq/QytNuEM +rkvF7zuZ2SOzW120V+x0cAwqTwIDAQABo4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAy +oDCgLoYsaHR0cDovL2ZlZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0P +AQH/BAQDAgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRLAZs+ +VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWdfoPPbrxHbvUanlR2 +QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0McXS6hMTXcpuEfDhOZAYnKuGntewI +mbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb +/627HOkthIDYIb6FUtnUdLlphbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VG +zT2ouvDzuFYkRes3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U +AGegcQCCSA== +-----END CERTIFICATE----- + +ComSign Secured CA +================== +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE +AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w +NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD +QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs +49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH +7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB +kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 +9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw +AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t +U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA +j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC +AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a +BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp +FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP +51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 +============================================================================================================================= +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH +DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q +aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry +b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV +BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg +S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 +MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl +IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF +n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl +IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft +dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl +cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO +Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 +xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR +6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd +BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 +N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT +y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh +LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M +dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +Buypass Class 2 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 +MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M +cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 +0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 +0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R +uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV +1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt +7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 +fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w +wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +Buypass Class 3 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 +MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx +ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 +n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia +AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c +1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 +pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA +EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 +htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj +el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- + +EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 +========================================================================== +-----BEGIN CERTIFICATE----- +MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg +QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe +Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt +IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by +X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b +gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr +eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ +TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy +Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn +uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI +qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm +ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 +Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW +Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t +FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm +zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k +XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT +bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU +RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK +1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt +2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ +Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 +AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +CNNIC ROOT +========== +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE +ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw +OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD +o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz +VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT +VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or +czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK +y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC +wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S +lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 +Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM +O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 +BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 +G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m +mxE= +-----END CERTIFICATE----- + +ApplicationCA - Japanese Government +=================================== +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT +SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw +MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl +cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 +fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN +wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE +jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu +nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU +WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV +BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD +vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs +o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g +/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD +io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW +dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +============================================ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ +5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn +vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj +CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil +e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR +OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI +CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 +48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi +trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 +qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB +AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC +ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA +A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz ++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj +f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN +kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk +CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF +URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb +CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h +oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV +IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm +66+KAQ== +-----END CERTIFICATE----- + +CA Disig +======== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK +QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw +MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz +bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm +GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD +Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo +hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt +ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w +gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P +AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz +aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff +ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa +BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t +WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 +mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K +ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA +4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- + +Juur-SK +======= +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA +c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw +DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG +SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy +aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf +TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC ++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw +UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa +Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF +MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD +HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh +AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA +cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr +AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw +cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G +A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo +ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL +abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 +IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh +Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 +yyqcjg== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +ACEDICOM Root +============= +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD +T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 +MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG +A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk +WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD +YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew +MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb +m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk +HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT +xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 +3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 +2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq +TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz +4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU +9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv +bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg +aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP +eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk +zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 +ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI +KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq +nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE +I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp +MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o +tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== +-----END CERTIFICATE----- + +Verisign Class 1 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAx +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0fzGVuDLDQ +VoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHiTkVWaR94AoDa3EeRKbs2 +yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFgVKTk8d6Pa +XCUDfGD67gmZPCcQcMgMCeazh88K4hiWNWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n +0a3hUKw8fGJLj7qE1xIVGx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZ +RjXZ+Hxb +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky +CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX +bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ +D/xwzoiQ +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi +=================================================== +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz +ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 +MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 +cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u +aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY +8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y +jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI +JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk +9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG +SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d +F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq +D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 +Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq +fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +TC TrustCenter Universal CA III +=============================== +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe +Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU +QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex +KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt +QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO +juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut +CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1 +M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G +A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA +g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+ +KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK +BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV +CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq +woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +Certinomis - Autorité Racine +============================= +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg +LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG +A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw +JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa +wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly +Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw +2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N +jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q +c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC +lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb +xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g +530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna +4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x +WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva +R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 +nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B +CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv +JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE +qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b +WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE +wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ +vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +Root CA Generalitat Valenciana +============================== +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE +ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 +IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 +WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE +CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 +F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B +ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ +D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte +JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB +AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n +dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB +ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl +AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA +YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy +AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt +AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA +YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu +AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA +OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 +dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV +BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S +b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh +TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz +Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 +NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH +iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt ++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +A-Trust-nQual-03 +================ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE +Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R +dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw +RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 +ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 +c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA +zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n +yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE +SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 +iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V +cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV +eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 +ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr +sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd +JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 +ahq97BvIxYSazQ== +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Trustis FPS Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 +IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ +RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk +H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa +cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt +o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA +AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd +BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c +GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC +yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P +8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV +l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl +iB6XzCGcKQENZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ +Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 +dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu +c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv +bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 +aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 +fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm +N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN +Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T +tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX +e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA +2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs +HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib +D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= +-----END CERTIFICATE----- + +StartCom Certification Authority G2 +=================================== +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE +ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O +o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG +4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi +Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul +Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs +O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H +vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L +nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS +FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa +z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ +KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk +J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ +JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG +/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc +nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld +blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc +l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm +7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm +obp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- + +cacert.class3 +============= +-----BEGIN CERTIFICATE----- +MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv +b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ +Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y +dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU +MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 +Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a +iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 +aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C +jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia +pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 +FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt +XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL +oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 +R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp +rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ +LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA +BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow +gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV +BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG +A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH +AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr +BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB +MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y +Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj +ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 +b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D +QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc +7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH +Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 +D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 +VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a +lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW +Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt +hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz +0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn +ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT +d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 +4GGSt/M3mMS+lqO3ig== +-----END CERTIFICATE----- + +cacert.root +=========== +-----BEGIN CERTIFICATE----- +MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 +IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB +IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA +Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO +BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi +MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ +ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ +8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 +zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y +fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 +w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc +G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k +epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q +laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ +QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU +fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 +YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w +ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY +gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe +MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 +IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy +dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw +czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 +dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl +aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC +AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg +b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB +ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc +nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg +18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c +gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl +Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY +sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T +SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF +CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum +GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk +zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW +omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD +-----END CERTIFICATE----- + +github.com +========== +-----BEGIN CERTIFICATE----- +MIIHKjCCBhKgAwIBAgIQDnd2il0H8OV5WcoqnVCCtTANBgkqhkiG9w0BAQUFADBp +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSgwJgYDVQQDEx9EaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBDQS0xMB4XDTExMDUyNzAwMDAwMFoXDTEzMDcyOTEyMDAwMFowgcoxHTAb +BgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVT +MRswGQYLKwYBBAGCNzwCAQITCkNhbGlmb3JuaWExETAPBgNVBAUTCEMzMjY4MTAy +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2Fu +IEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRo +dWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7dOJw11wcgnz +M08acnTZtlqVULtoYZ/3+x8Z4doEMa8VfBp/+XOvHeVDK1YJAEVpSujEW9/Cd1JR +GVvRK9k5ZTagMhkcQXP7MrI9n5jsglsLN2Q5LLcQg3LN8OokS/rZlC7DhRU5qTr2 +iNr0J4mmlU+EojdOfCV4OsmDbQIXlXh9R6hVg+4TyBkaszzxX/47AuGF+xFmqwld +n0xD8MckXilyKM7UdWhPJHIprjko/N+NT02Dc3QMbxGbp91i3v/i6xfm/wy/wC0x +O9ZZovLdh0pIe20zERRNNJ8yOPbIGZ3xtj3FRu9RC4rGM+1IYcQdFxu9fLZn6TnP +pVKACvTqzQIDAQABo4IDajCCA2YwHwYDVR0jBBgwFoAUTFjLJfBBT1L0KMiBQ5um +qKDmkuUwHQYDVR0OBBYEFIfRjxlu5IdvU4x3kQdQ36O/VUcgMCUGA1UdEQQeMByC +CmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMIGBBggrBgEFBQcBAQR1MHMwJAYI +KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBLBggrBgEFBQcwAoY/ +aHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ0FDZXJ0cy9EaWdpQ2VydEhpZ2hBc3N1 +cmFuY2VFVkNBLTEuY3J0MAwGA1UdEwEB/wQCMAAwYQYDVR0fBFowWDAqoCigJoYk +aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL2V2MjAwOWEuY3JsMCqgKKAmhiRodHRw +Oi8vY3JsNC5kaWdpY2VydC5jb20vZXYyMDA5YS5jcmwwggHEBgNVHSAEggG7MIIB +tzCCAbMGCWCGSAGG/WwCATCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGln +aWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCC +AVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABp +AGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBw +AHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQ +AC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQBy +AHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0 +ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwBy +AHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBl +AG4AYwBlAC4wHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBEGCWCGSAGG ++EIBAQQEAwIGwDAOBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBABRS +cR+GnW01Poa7ZhqLhZi5AEzLQrVG/AbnRDnI6FLYERQjs3KW6RSUni8AKPfVBEVA +AMb0V0JC3gmJlxENFFxrvQv3GKNfZwLzCThjv8ESnTC6jqVUdFlTZ6EbUFsm2v0T +flkXv0nvlH5FpP06STLwav+JjalhqaqblkbIHOAYHOb7gvQKq1KmyuhUItnbKj1a +InuA6gcF1PnH8FNZX7t3ft6TcEFOI8t4eXnELurXZioY99HFfOISeIKNHeyCngGi +5QK+eKG5WVjFTG9PpTG0SVtemB4uOPYZxDmiSvt5BbjyWeUmEnCtwOh1Ix8Y0Qvg +n2Xkw9dJh1tybLEvrG8= +-----END CERTIFICATE----- + +www.kernel.org +============== +-----BEGIN CERTIFICATE----- +MIIEDjCCA3egAwIBAgICECMwDQYJKoZIhvcNAQEFBQAwgbsxCzAJBgNVBAYTAi0t +MRIwEAYDVQQIEwlTb21lU3RhdGUxETAPBgNVBAcTCFNvbWVDaXR5MRkwFwYDVQQK +ExBTb21lT3JnYW5pemF0aW9uMR8wHQYDVQQLExZTb21lT3JnYW5pemF0aW9uYWxV +bml0MR4wHAYDVQQDExVsb2NhbGhvc3QubG9jYWxkb21haW4xKTAnBgkqhkiG9w0B +CQEWGnJvb3RAbG9jYWxob3N0LmxvY2FsZG9tYWluMB4XDTA3MDQyMDE3NTEyMFoX +DTA4MDQxOTE3NTEyMFowgbsxCzAJBgNVBAYTAi0tMRIwEAYDVQQIEwlTb21lU3Rh +dGUxETAPBgNVBAcTCFNvbWVDaXR5MRkwFwYDVQQKExBTb21lT3JnYW5pemF0aW9u +MR8wHQYDVQQLExZTb21lT3JnYW5pemF0aW9uYWxVbml0MR4wHAYDVQQDExVsb2Nh +bGhvc3QubG9jYWxkb21haW4xKTAnBgkqhkiG9w0BCQEWGnJvb3RAbG9jYWxob3N0 +LmxvY2FsZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPJTvJ9DPn +DLLRBHcW7LunMJIjDitjA5hrOE2jIf4PgLwRXoHSens4Rr9dlxJ4ffP12oGoPJ4e +V9CVEq0cB7pBVAHpGSYnuDRj4kLmOwtY2QX5wQ8jJHgFK1yMGWB+8SGVbp/suDVE +9VTmNFXYNTzqwBMog3hsWrCGIGy/MQNX8QIDAQABo4IBHTCCARkwHQYDVR0OBBYE +FPSTDcX+uTjwbVNyqpze6fPudFKgMIHpBgNVHSMEgeEwgd6AFPSTDcX+uTjwbVNy +qpze6fPudFKgoYHBpIG+MIG7MQswCQYDVQQGEwItLTESMBAGA1UECBMJU29tZVN0 +YXRlMREwDwYDVQQHEwhTb21lQ2l0eTEZMBcGA1UEChMQU29tZU9yZ2FuaXphdGlv +bjEfMB0GA1UECxMWU29tZU9yZ2FuaXphdGlvbmFsVW5pdDEeMBwGA1UEAxMVbG9j +YWxob3N0LmxvY2FsZG9tYWluMSkwJwYJKoZIhvcNAQkBFhpyb290QGxvY2FsaG9z +dC5sb2NhbGRvbWFpboICECMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB +gQAT9vvcnJaGGE67YJvt1VgsMt6wHFgLZo9vOZF9/Bw6a3cm4E/teMuZJe/gxImG +r2H4jMYgwgBonAFwZYpVmpz65vKzZA9vSe9xbxpAl22wLQUFsEH7d3TZjCst3gf1 +ZdC+RbpUoH2iXlZhifkdI4ZgOL+KHy3v6+Rv1rGFjvhgRw== +-----END CERTIFICATE----- diff --git a/data/language/dutch.txt b/data/language/dutch.txt index 402b6a227b..db170d4a2b 100644 --- a/data/language/dutch.txt +++ b/data/language/dutch.txt @@ -1,96 +1,96 @@ STR_0000 : STR_0001 :{STRINGID} {COMMA16} -STR_0002 :Attractie -STR_0003 :Attractie +STR_0002 :Spiraalachtbaan +STR_0003 :Staande achtbaan STR_0004 :Omgekeerde schommelachtbaan -STR_0005 :Attractie +STR_0005 :Omgekeerde achtbaan STR_0006 :Juniorachtbaan STR_0007 :Miniatuurspoorweg STR_0008 :Monorail -STR_0009 :Omgekeerde miniachtbaan -STR_0010 :Attractie -STR_0011 :Attractie -STR_0012 :Attractie +STR_0009 :Omgekeerde mini-achtbaan +STR_0010 :Bootverhuur +STR_0011 :Houten wildemuisachtbaan +STR_0012 :Steeplechase STR_0013 :Autorondrit -STR_0014 :Attractie -STR_0015 :Attractie -STR_0016 :Attractie +STR_0014 :Gelanceerde vrije val +STR_0015 :Bobslee-achtbaan +STR_0016 :Observatietoren STR_0017 :Stalen achtbaan -STR_0018 :Attractie -STR_0019 :Attractie +STR_0018 :Waterglijbaan +STR_0019 :Mijntreinachtbaan STR_0020 :Kabelbaan -STR_0021 :Attractie -STR_0022 :Attractie -STR_0023 :Attractie -STR_0024 :Attractie -STR_0025 :Attractie -STR_0026 :Attractie -STR_0027 :Attractie -STR_0028 :Attractie -STR_0029 :Attractie -STR_0030 :Kraam -STR_0031 :Kraam -STR_0032 :Kraam -STR_0033 :Kraam -STR_0034 :Kraam -STR_0035 :Attractie -STR_0036 :Kraam -STR_0037 :Kiosk +STR_0021 :Stalen schroefachtbaan +STR_0022 :Doolhof +STR_0023 :Spiraalglijbaan +STR_0024 :Go Karts +STR_0025 :Boomstamattractie +STR_0026 :Wildwaterbaan +STR_0027 :Botsauto's +STR_0028 :Schommelschip +STR_0029 :Schommelschip dat over de kop gaat +STR_0030 :Eetkraam +STR_0031 :Onbekende kraam (1D) +STR_0032 :Drankkraam +STR_0033 :Onbekende kraam (1F) +STR_0034 :Winkel +STR_0035 :Draaimolen +STR_0036 :Onbekende kraam (22) +STR_0037 :Informatiekiosk STR_0038 :Toilet -STR_0039 :Attractie -STR_0040 :Attractie -STR_0041 :Attractie -STR_0042 :Attractie -STR_0043 :Attractie +STR_0039 :Reuzenrad +STR_0040 :Bewegingssimulator +STR_0041 :3D-bioscoop +STR_0042 :Topspin +STR_0043 :Ruimteringen STR_0044 :Omgekeerde vrijevalachtbaan STR_0045 :Lift -STR_0046 :Attractie -STR_0047 :Attractie -STR_0048 :Attractie -STR_0049 :Attractie -STR_0050 :Attractie -STR_0051 :Attractie -STR_0052 :Attractie -STR_0053 :Hyper-Twisterachtbaan +STR_0046 :Verticale achtbaan +STR_0047 :Geldautomaat +STR_0048 :Twist +STR_0049 :Spookhuis +STR_0050 :Eerste hulp +STR_0051 :Circus +STR_0052 :Spooktrein +STR_0053 :Hyper-twisterachtbaan STR_0054 :Houten achtbaan -STR_0055 :Zijfrictieachtbaan +STR_0055 :Zijfrictie-achtbaan STR_0056 :Wilde muis -STR_0057 :Multidimensieachtbaan -STR_0058 :Attractie +STR_0057 :Multidimensie-achtbaan +STR_0058 :Onbekende attractie (38) STR_0059 :Omgekeerde luchtachtbaan -STR_0060 :Attractie -STR_0061 :Attractie -STR_0062 :Attractie -STR_0063 :Attractie -STR_0064 :Attractie +STR_0060 :Onbekende attractie (3A) +STR_0061 :Virginia Reel +STR_0062 :Plonsboten +STR_0063 :Minihelikopters +STR_0064 :Liggende achtbaan STR_0065 :Omgekeerde monorail -STR_0066 :Attractie -STR_0067 :Attractie +STR_0066 :Onbekende attractie (40) +STR_0067 :Houten achteruitachtbaan STR_0068 :Heartline-twisterachtbaan -STR_0069 :Attractie -STR_0070 :Attractie -STR_0071 :Attractie -STR_0072 :Attractie -STR_0073 :Attractie -STR_0074 :Attractie -STR_0075 :Attractie +STR_0069 :Minigolf +STR_0070 :Giga-achtbaan +STR_0071 :Roto-drop +STR_0072 :Vliegende schotels +STR_0073 :Crooked house +STR_0074 :Fietsbaan +STR_0075 :Compacte omgekeerde achtbaan STR_0076 :Waterachtbaan -STR_0077 :Attractie -STR_0078 :Attractie -STR_0079 :Attractie -STR_0080 :Attractie -STR_0081 :Attractie -STR_0082 :Attractie -STR_0083 :Attractie -STR_0084 :Attractie -STR_0085 :Attractie -STR_0086 :Attractie -STR_0087 :Attractie -STR_0088 :Attractie -STR_0089 :Miniachtbaan -STR_0090 :Attractie -STR_0091 :Attractie -STR_0092 :Attractie +STR_0077 :Luchtaangedreven verticale achtbaan +STR_0078 :Omgekeerde haarspeldachtbaan +STR_0079 :Vliegend tapijt +STR_0080 :Onderzeeër-attractie +STR_0081 :Riviertocht +STR_0082 :Onbekende attractie (50) +STR_0083 :Enterprise +STR_0084 :Onbekende attractie (52) +STR_0085 :Onbekende attractie (53) +STR_0086 :Onbekende attractie (54) +STR_0087 :Onbekende attractie (55) +STR_0088 :Omgekeerde Impulse-achtbaan +STR_0089 :Mini-achtbaan +STR_0090 :Aandreven mijntrein +STR_0091 :Onbekende attractie (59) +STR_0092 :LIM-lanceringsachtbaan STR_0093 : STR_0094 : STR_0095 : @@ -512,7 +512,7 @@ STR_0510 : STR_0511 : STR_0512 : STR_0513 : -STR_0514 :Treinen hangen onder de baan en zwaaien naar buiten in bochten +STR_0514 :Treinen hangen onder de baan en zwaaien naar buiten in de bochten STR_0515 : STR_0516 :Een rustige achtbaan voor bezoekers die nog niet in engere attracties durven STR_0517 :Passagiers rijden in miniatuurtreinen over een smalspoorweg @@ -564,10 +564,10 @@ STR_0562 : STR_0563 :Bezoekers zitten in comfortabele treinen met enkel een schootbeugel en gaan soepel door grote afdalingen en kronkelende stukken baan, met veel 'airtime' in de heuvels STR_0564 :Deze over een houten baan lopende achtbaan is snel, ruw, luidruchting en geeft het gevoel van controleverlies met veel 'airtime' STR_0565 :Een simpele houten achtbaan die enkel in staat is rustige hellingen en bochten te bedwingen, de karretjes worden enkel op de baan gehouden door middel van zijfrictiewielen en zwaartekracht -STR_0566 :Losse karretjes rijden over een kronkelende baan scherpe bochten en korte felle afdalingen -STR_0567 :Bezoekers zitten in stoelen aan beide kanten van de baan, en draaien alle kanten op terwijl ze door de diepe afdalingen gaan en door diverse omkeringen. +STR_0566 :Losse karretjes rijden over een kronkelende baan met scherpe bochten en korte felle afdalingen +STR_0567 :Bezoekers zitten in stoelen aan beide kanten van de baan, en draaien alle kanten op terwijl ze door diepe afdalingen en diverse omkeringen gaan STR_0568 : -STR_0569 :Bezoekers zitten in een speciaal tuigje onder de baan en krijgen zo de ervaring dat ze vliegen +STR_0569 :Bezoekers hangen in treinen onder de baan met enkel schouderbeugels en krijgen zo de ervaring dat ze vliegen STR_0570 : STR_0571 : STR_0572 : @@ -576,7 +576,7 @@ STR_0574 : STR_0575 :Aangedreven treinen hangen aan een enkele rail en vervoeren mensen door het park heen STR_0576 : STR_0577 : -STR_0578 :Karretjes lopen in een baan omgeven door hoepels en gaan door steile afdalingen en heartline-twists +STR_0578 :Karretjes rijden in een baan omgeven door hoepels en gaan door steile afdalingen en heartline-twists STR_0579 : STR_0580 : STR_0581 : @@ -584,7 +584,7 @@ STR_0582 : STR_0583 : STR_0584 : STR_0585 : -STR_0586 :Bootvormige karretjes lopen over achtbaanrails, waardoor ze hellende bochten en diepe afdalingen kunnen maken, waarna ze in bakken water neerplonzen en rustig een stukje kunnen varen +STR_0586 :Bootvormige karretjes rijden over achtbaanrails, waardoor ze hellende bochten en diepe afdalingen kunnen maken, waarna ze in bakken water neerplonzen en rustig een stukje kunnen varen STR_0587 : STR_0588 : STR_0589 : @@ -1059,42 +1059,42 @@ STR_1057 :Attractienaam STR_1058 :Voer een nieuwe naam in voor deze attractie: STR_1059 :Kan deze attractie geen andere naam geven... STR_1060 :Ongeldige attractienaam -STR_1061 :Normale stand +STR_1061 :Normale modus STR_1062 :Voortdurend circuit STR_1063 :Lancering via achterwaartse optakeling -STR_1064 :Lancering -STR_1065 :Shuttlestand +STR_1064 :Lancering (station passeren) +STR_1065 :Shuttlemodus STR_1066 :Bootverhuurmodus STR_1067 :Opwaartse lancering STR_1068 :Draaiendeliftmodus STR_1069 :Station-naar-station STR_1070 :Enkele rit per entree STR_1071 :Onbeperkt aantal ritten per entree -STR_1072 :Doolhofstand -STR_1073 :Racestand +STR_1072 :Doolhofmodus +STR_1073 :Racemodus STR_1074 :Botsautomodus -STR_1075 :Schommelstand -STR_1076 :Winkelstand -STR_1077 :Draaistand +STR_1075 :Schommelmodus +STR_1076 :Winkelmodus +STR_1077 :Draaimodus STR_1078 :Voorwaartse rotatie STR_1079 :Achterwaartse rotatie -STR_1080 :Film: {ENDQUOTES}Avenging aviators{ENDQUOTES} -STR_1081 :3D-film: {ENDQUOTES}Mouse tails{ENDQUOTES} +STR_1080 :Film: {ENDQUOTES}Avenging Aviators{ENDQUOTES} +STR_1081 :3D-film: {ENDQUOTES}Mouse Tails{ENDQUOTES} STR_1082 :Ruimteringenmodus STR_1083 :Beginnersstand STR_1084 :LIM-lancering -STR_1085 :Film: {ENDQUOTES}Thrill riders{ENDQUOTES} -STR_1086 :3D-film: {ENDQUOTES}Storm chasers{ENDQUOTES} -STR_1087 :3D-film: {ENDQUOTES}Space raiders{ENDQUOTES} +STR_1085 :Film: {ENDQUOTES}Thrill Riders{ENDQUOTES} +STR_1086 :3D-film: {ENDQUOTES}Storm Chasers{ENDQUOTES} +STR_1087 :3D-film: {ENDQUOTES}Space Raiders{ENDQUOTES} STR_1088 :Intense stand -STR_1089 :Gestoorde stand +STR_1089 :Waanzinnige stand STR_1090 :Spookhuismodus STR_1091 :Circusmodus STR_1092 :Neerwaartse lancering -STR_1093 :Crooked housestand +STR_1093 :Crookedhousemodus STR_1094 :Vrijevalmodus STR_1095 :Voortdurend circuit met blokken -STR_1096 :Lancering +STR_1096 :Lancering (station niet passeren) STR_1097 :Lancering met blokken STR_1098 :Gaat naar het einde van {POP16}{STRINGID} STR_1099 :Wacht op passagiers op {POP16}{STRINGID} @@ -1171,13 +1171,13 @@ STR_1169 :(Geen) STR_1170 :{STRING} STR_1171 :{RED}Gesloten - - STR_1172 :{YELLLOW}{STRINGID} - - -STR_1173 :{SMALLFONT}{BLACK}Voetpaden en wachtrijen neerzetten -STR_1174 :Banier in de weg +STR_1173 :{SMALLFONT}{BLACK}Voetpaden en wachtrijen aanleggen +STR_1174 :Lichtkrant in de weg STR_1175 :Kan dit niet op hellend voetpad neerzetten -STR_1176 :Kan hier geen voetpad neerzetten... +STR_1176 :Kan hier geen voetpad aanleggen... STR_1177 :Kan dit voetpad niet verwijderen... STR_1178 :Landhelling is ongeschikt -STR_1179 :Voetpad staat in de weg +STR_1179 :Voetpad ligt in de weg STR_1180 :Dit kan niet onder water worden gebouwd! STR_1181 :Voetpaden STR_1182 :Type @@ -1338,14 +1338,14 @@ STR_1336 :{STRINGID} - Ingang station {POP16}{COMMA16} STR_1337 :{STRINGID} - Uitgang{POP16}{POP16} STR_1338 :{STRINGID} - Uitgang station {POP16}{COMMA16} STR_1339 :{BLACK}Nog geen testresultaten... -STR_1340 :{WINDOW_COLOUR_2}Max. snlhd: {BLACK}{VELOCITY} +STR_1340 :{WINDOW_COLOUR_2}Max. snelheid: {BLACK}{VELOCITY} STR_1341 :{WINDOW_COLOUR_2}Ritduur: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} STR_1342 :{DURATION} STR_1343 :{DURATION} / STR_1344 :{WINDOW_COLOUR_2}Lengte: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} STR_1345 :{LENGTH} STR_1346 :{LENGTH} / -STR_1347 :{WINDOW_COLOUR_2}Gem. snlhd: {BLACK}{VELOCITY} +STR_1347 :{WINDOW_COLOUR_2}Gem. snelheid: {BLACK}{VELOCITY} STR_1348 :{WINDOW_COLOUR_2}Max. pos. vert. G-krachten: {BLACK}{COMMA2DP32}g STR_1349 :{WINDOW_COLOUR_2}Max. pos. vert. G-krachten: {OUTLINE}{RED}{COMMA2DP32}g STR_1350 :{WINDOW_COLOUR_2}Max. neg. vert. G-krachten: {BLACK}{COMMA2DP32}g @@ -1500,7 +1500,7 @@ STR_1498 :{SMALLFONT}{OPENQUOTES}Ik sta al eeuwen in de rij voor {STRINGID}{E STR_1499 :{SMALLFONT}{OPENQUOTES}Ik ben moe{ENDQUOTES} STR_1500 :{SMALLFONT}{OPENQUOTES}Ik heb honger{ENDQUOTES} STR_1501 :{SMALLFONT}{OPENQUOTES}Ik heb dorst{ENDQUOTES} -STR_1502 :{SMALLFONT}{OPENQUOTES}Ik moet naar de WC{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}Ik moet naar de wc{ENDQUOTES} STR_1503 :{SMALLFONT}{OPENQUOTES}Ik kan {STRINGID} niet vinden{ENDQUOTES} STR_1504 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor het gebruik van {STRINGID}{ENDQUOTES} STR_1505 :{SMALLFONT}{OPENQUOTES}Ik ga niet in {STRINGID} als het regent{ENDQUOTES} @@ -1588,7 +1588,7 @@ STR_1586 :{SMALLFONT}{OPENQUOTES}Deze actiefoto van {STRINGID} is erg goedkoo STR_1587 :{SMALLFONT}{OPENQUOTES}Deze krakeling van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1588 :{SMALLFONT}{OPENQUOTES}Deze warme chocolademelk van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1589 :{SMALLFONT}{OPENQUOTES}Deze ijsthee van {STRINGID} is erg goedkoop{ENDQUOTES} -STR_1590 :{SMALLFONT}{OPENQUOTES}Deze funnel cake van {STRINGID} is erg goedkoop{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}Deze oliebollen van {STRINGID} zijn erg goedkoop{ENDQUOTES} STR_1591 :{SMALLFONT}{OPENQUOTES}Deze zonnebril van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1592 :{SMALLFONT}{OPENQUOTES}Deze rundernoedels van {STRINGID} zijn erg goedkoop{ENDQUOTES} STR_1593 :{SMALLFONT}{OPENQUOTES}Deze rijstnoedels van {STRINGID} zijn erg goedkoop{ENDQUOTES} @@ -1620,7 +1620,7 @@ STR_1618 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een actiefoto van STR_1619 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een krakeling van {STRINGID}{ENDQUOTES} STR_1620 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor warme chocolademelk van {STRINGID}{ENDQUOTES} STR_1621 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor ijsthee van {STRINGID}{ENDQUOTES} -STR_1622 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een funnel cake van {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een oliebol van {STRINGID}{ENDQUOTES} STR_1623 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een zonnebril van {STRINGID}{ENDQUOTES} STR_1624 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor rundernoedels van {STRINGID}{ENDQUOTES} STR_1625 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor rijstnoedels van {STRINGID}{ENDQUOTES} @@ -1653,19 +1653,19 @@ STR_1651 :{SMALLFONT}{OPENQUOTES}Leuke attractie! Maar niet zo goed als de Ph STR_1652 :{SMALLFONT}{OPENQUOTES}Ik ben zo enthousiast - het is een attractie van Intamin!{ENDQUOTES} STR_1653 :{SMALLFONT}{OPENQUOTES}...en nu zijn we in {STRINGID}!{ENDQUOTES} STR_1654 :{WINDOW_COLOUR_2}Recente gedachten: -STR_1655 :{SMALLFONT}{BLACK}Voetpaden op land bouwen -STR_1656 :{SMALLFONT}{BLACK}Voetpad over bruggen of door tunnels bouwen +STR_1655 :{SMALLFONT}{BLACK}Voetpaden op land aanleggen +STR_1656 :{SMALLFONT}{BLACK}Voetpad over bruggen of door tunnels aanleggen STR_1657 :{WINDOW_COLOUR_2}Voorkeursintensiteit: STR_1658 :{WINDOW_COLOUR_2}{BLACK}minder dan {COMMA16} STR_1659 :{WINDOW_COLOUR_2}{BLACK}tussen {COMMA16} en {COMMA16} STR_1660 :{WINDOW_COLOUR_2}{BLACK}meer dan {COMMA16} STR_1661 :{WINDOW_COLOUR_2}Misselijkheidstolerantie: {BLACK}{STRINGID} STR_1662 :{WINDOW_COLOUR_2}Stemming: -STR_1663 :{WINDOW_COLOUR_2}Misselijkheid: +STR_1663 :{WINDOW_COLOUR_2}Misselijkh.: STR_1664 :{WINDOW_COLOUR_2}Energie: STR_1665 :{WINDOW_COLOUR_2}Honger: STR_1666 :{WINDOW_COLOUR_2}Dorst: -STR_1667 :{WINDOW_COLOUR_2}WC-behoefte: +STR_1667 :{WINDOW_COLOUR_2}Wc-beh.: STR_1668 :{WINDOW_COLOUR_2}Voldoening: {BLACK}onbekend STR_1669 :{WINDOW_COLOUR_2}Voldoening: {BLACK}{COMMA16}% STR_1670 :{WINDOW_COLOUR_2}Totaal aantal bezoekers: {BLACK}{COMMA32} @@ -1694,7 +1694,7 @@ STR_1692 :{WINDOW_COLOUR_2} Kosten: {BLACK}vanaf {CURRENCY} STR_1693 :{SMALLFONT}{BLACK}Bezoekers STR_1694 :{SMALLFONT}{BLACK}Werknemers STR_1695 :{SMALLFONT}{BLACK}Inkomsten en kosten -STR_1696 :{SMALLFONT}{BLACK}Klanteninformatie +STR_1696 :{SMALLFONT}{BLACK}Klantinformatie STR_1697 :Dit kan niet op wachtrijen worden geplaatst STR_1698 :Dit kan alleen op wachtrijen worden geplaatst STR_1699 :Teveel personen in het spel @@ -1710,10 +1710,10 @@ STR_1708 :{SMALLFONT}{BLACK}Werkgebied van deze werknemer instellen STR_1709 :Werknemer ontslaan STR_1710 :Ja STR_1711 :{WINDOW_COLOUR_1}Weet je zeker dat je {STRINGID} wilt ontslaan? -STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2} -STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2} -STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2} -STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2} +STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2}Voetpaden vegen +STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2}Bloemen water geven +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Prullenbakken legen +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Gras maaien STR_1716 :Ongeldige parknaam STR_1717 :Kan het park geen andere naam geven... STR_1718 :Parknaam @@ -1775,7 +1775,7 @@ STR_1773 :Een attractie mag maar één actiefotogedeelte hebben STR_1774 :Een attractie mag maar één kabellift hebben STR_1775 :Uit STR_1776 :Aan -STR_1777 :{WINDOW_COLOUR_2}Muziek: +STR_1777 :{WINDOW_COLOUR_2}Muziek STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Pandapak STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tijgerpak @@ -1787,7 +1787,7 @@ STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Ridderkostuum STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronautenpak STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandietenkostuum STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriffkostuum -STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Piratenpak +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Piratenkostuum STR_1790 :{SMALLFONT}{BLACK}Selecteer de uniformkleur voor dit type werknemer STR_1791 :{WINDOW_COLOUR_2}Uniformkleur: STR_1792 :Gaat {STRINGID} repareren @@ -1839,7 +1839,7 @@ STR_1837 :Voldoening: onbekend STR_1838 :Voldoening: {COMMA16}% STR_1839 :Betrouwbaarheid: {COMMA16}% STR_1840 :Stilstandtijd: {COMMA16}% -STR_1841 :Winst: {CURRENCY} per uur +STR_1841 :Winst: {CURRENCY2DP} per uur STR_1842 :Favoriete attractie van: {COMMA16} bezoeker STR_1843 :Favoriete attractie van: {COMMA16} bezoekers STR_1844 :{SMALLFONT}{BLACK}Selecteer het type informatie dat je in de attractielijst wilt zien @@ -1856,7 +1856,7 @@ STR_1854 :{WINDOW_COLOUR_2}Bouw: {BLACK}vorig jaar STR_1855 :{WINDOW_COLOUR_2}Bouw: {BLACK}{COMMA16} jaar geleden STR_1856 :{WINDOW_COLOUR_2}Winst per verkocht artikel: {BLACK}{CURRENCY2DP} STR_1857 :{WINDOW_COLOUR_2}Verlies per verkocht artikel: {BLACK}{CURRENCY2DP} -STR_1858 :{WINDOW_COLOUR_2}Kosten: {BLACK}{CURRENCY} per maand +STR_1858 :{WINDOW_COLOUR_2}Kosten: {BLACK}{CURRENCY2DP} per maand STR_1859 :Klusjesmannen STR_1860 :Monteurs STR_1861 :Bewakers @@ -1871,16 +1871,16 @@ STR_1869 :{WINDOW_COLOUR_2}Aantal rotaties: STR_1870 :{SMALLFONT}{BLACK}Aantal complete rotaties STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1872 :{COMMA16} -STR_1873 :{WINDOW_COLOUR_2}Inkomsten: {BLACK}{CURRENCY} per uur -STR_1874 :{WINDOW_COLOUR_2}Winst: {BLACK}{CURRENCY} per uur +STR_1873 :{WINDOW_COLOUR_2}Inkomsten: {BLACK}{CURRENCY2DP} per uur +STR_1874 :{WINDOW_COLOUR_2}Winst: {BLACK}{CURRENCY2DP} per uur STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Attracties inspecteren STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Attracties repareren STR_1878 :{WINDOW_COLOUR_2}Inspectie: STR_1879 :Elke 10 minuten -STR_1880 :Elke 20 minutes -STR_1881 :Elke 30 minutes -STR_1882 :Elke 45 minutes +STR_1880 :Elke 20 minuten +STR_1881 :Elke 30 minuten +STR_1882 :Elke 45 minuten STR_1883 :Elk uur STR_1884 :Elke 2 uur STR_1885 :Nooit @@ -1928,7 +1928,7 @@ STR_1926 :{SMALLFONT} STR_1927 :{YELLOW}{STRINGID} is kapot gegaan STR_1928 :{RED}{STRINGID} is neergestort! STR_1929 :{RED}{STRINGID} is nog steeds niet gerepareerd{NEWLINE}Controleer waar je monteurs zijn en overweeg ze beter te organiseren -STR_1930 :{SMALLFONT}{BLACK}Volgen van bezoeker aan- of uitschakelen - (Als volgen is ingeschakeld, worden de activiteit van deze bezoeker vermeld in het berichtengebied) +STR_1930 :{SMALLFONT}{BLACK}Volgen van bezoeker in- of uitschakelen - (Als volgen is ingeschakeld, worden de activiteiten van deze bezoeker vermeld in het berichtengebied) STR_1931 :{STRINGID} staat nu in de rij voor {STRINGID} STR_1932 :{STRINGID} is nu in {STRINGID} STR_1933 :{STRINGID} is nu in {STRINGID} @@ -2104,7 +2104,7 @@ STR_2102 :{WINDOW_COLOUR_2}Prijs actiefoto: STR_2103 :{WINDOW_COLOUR_2}Prijs krakeling: STR_2104 :{WINDOW_COLOUR_2}Prijs warme chocolademelk: STR_2105 :{WINDOW_COLOUR_2}Prijs ijsthee: -STR_2106 :{WINDOW_COLOUR_2}Prijs funnel cake: +STR_2106 :{WINDOW_COLOUR_2}Prijs oliebollen: STR_2107 :{WINDOW_COLOUR_2}Prijs zonnebril: STR_2108 :{WINDOW_COLOUR_2}Prijs rundernoedels: STR_2109 :{WINDOW_COLOUR_2}Prijs rijstnoedels: @@ -2126,7 +2126,7 @@ STR_2124 :Actiefoto STR_2125 :Krakeling STR_2126 :Warme chocolademelk STR_2127 :IJsthee -STR_2128 :Funnel cake +STR_2128 :Oliebol STR_2129 :Zonnebril STR_2130 :Rundernoedels STR_2131 :Rijstnoedels @@ -2148,7 +2148,7 @@ STR_2146 :Actiefoto's STR_2147 :Krakelingen STR_2148 :Warme chocolademelk STR_2149 :IJsthee -STR_2150 :Funnel cakes +STR_2150 :Oliebollen STR_2151 :Zonnebrillen STR_2152 :Rundernoedels STR_2153 :Rijstnoedels @@ -2170,7 +2170,7 @@ STR_2168 :een actiefoto STR_2169 :een krakeling STR_2170 :warme chocolademelk STR_2171 :ijsthee -STR_2172 :een funnel cake +STR_2172 :een oliebol STR_2173 :een zonnebril STR_2174 :rundernoedels STR_2175 :rijstnoedels @@ -2192,7 +2192,7 @@ STR_2190 :Actiefoto van {STRINGID} STR_2191 :Krakeling STR_2192 :Warme chocolademelk STR_2193 :IJsthee -STR_2194 :Funnel cake +STR_2194 :Oliebollen STR_2195 :Zonnebril STR_2196 :Rundernoedels STR_2197 :Rijstnoedels @@ -2297,13 +2297,13 @@ STR_2295 :{SMALLFONT}{BLACK}Zijkant land aanpassen STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} betaald voor entree STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} attractie STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} attracties -STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} stuk voedsel -STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} stuks voedsel +STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} etenswaar +STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} etenswaren STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} drankje STR_2302 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} drankjes STR_2303 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} souvenir STR_2304 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} souvenirs -STR_2305 :Baantontwerpbestanden +STR_2305 :Baanontwerpbestanden STR_2306 :Baanontwerp opslaan STR_2307 :Ontwerp voor {STRINGID} selecteren STR_2308 :Baanontwerpen voor {STRINGID} @@ -2311,7 +2311,7 @@ STR_2309 :Nieuw baanontwerp installeren STR_2310 :Eigen ontwerp bouwen STR_2311 :{WINDOW_COLOUR_2}Spanningswaarde: {BLACK}{COMMA2DP32} (ongeveer) STR_2312 :{WINDOW_COLOUR_2}Intensiteitswaarde: {BLACK}{COMMA2DP32} (ongeveer) -STR_2313 :{WINDOW_COLOUR_2}Missellijkheidswaarde: {BLACK}{COMMA2DP32} (ongeveer) +STR_2313 :{WINDOW_COLOUR_2}Misselijkheidswaarde: {BLACK}{COMMA2DP32} (ongeveer) STR_2314 :{WINDOW_COLOUR_2}Lengte: {BLACK}{STRINGID} STR_2315 :{WINDOW_COLOUR_2}Kosten: {BLACK}ongeveer {CURRENCY} STR_2316 :{WINDOW_COLOUR_2}Vereiste ruimte: {BLACK}{COMMA16} x {COMMA16} blokken @@ -2339,7 +2339,7 @@ STR_2337 :Duitse mark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseta (Pts) STR_2340 :Lire (L) -STR_2341 :Guldens (fl.) +STR_2341 :Guldens (fl) STR_2342 :Kronen (kr) STR_2343 :Euro's ({EURO}) STR_2344 :Engelse maten @@ -2347,7 +2347,7 @@ STR_2345 :Metriek stelsel STR_2346 :Weergave STR_2347 :{RED}{STRINGID} is verdronken! STR_2348 :{SMALLFONT}{BLACK}Statistieken voor deze werknemer tonen -STR_2349 :{WINDOW_COLOUR_2}Loon: {BLACK}{CURRENCY} per month +STR_2349 :{WINDOW_COLOUR_2}Loon: {BLACK}{CURRENCY} per maand STR_2350 :{WINDOW_COLOUR_2}In dienst genomen: {BLACK}{MONTHYEAR} STR_2351 :{WINDOW_COLOUR_2}Velden gemaaid: {BLACK}{COMMA16} STR_2352 :{WINDOW_COLOUR_2}Bloemen water gegeven: {BLACK}{COMMA16} @@ -2360,7 +2360,7 @@ STR_2358 :Eenheden STR_2359 :Echte waarden STR_2360 :{WINDOW_COLOUR_2}Schermresolutie: STR_2361 :Landschapslijnen verzachten -STR_2362 :{SMALLFONT}{BLACK}Verzachting van lijnen tussen blokken land aan- of uitzetten +STR_2362 :{SMALLFONT}{BLACK}Verzachting van lijnen tussen landschapstegels aan- of uitzetten STR_2363 :Raster weergeven op landschap STR_2364 :{SMALLFONT}{BLACK}Rasterlijnen op land aan- of uitzetten STR_2365 :De bank wil je lening niet verhogen! @@ -2382,19 +2382,19 @@ STR_2380 :{SMALLFONT}{BLACK}Kleiner stuk water aanpassen STR_2381 :{SMALLFONT}{BLACK}Groter stuk water aanpassen STR_2382 :Land STR_2383 :Water -STR_2384 :{WINDOW_COLOUR_2}Je doel: +STR_2384 :{WINDOW_COLOUR_2}Je doelstelling: STR_2385 :{BLACK}Geen -STR_2386 :{BLACK}Om minstens {COMMA16} bezoekers in je park toe hebben aan het einde van {MONTHYEAR}, met een parkwaardering van ten minste 600 -STR_2387 :{BLACK}Om een parkwaarde van minstens {POP16}{POP16}{CURRENCY} te hebben aan het einde van {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR} +STR_2386 :{BLACK}Om ten minste {COMMA16} bezoekers in je park te hebben aan het einde van {MONTHYEAR}, met een parkwaardering van ten minste 600 +STR_2387 :{BLACK}Om een parkwaarde van ten minste {POP16}{POP16}{CURRENCY} te hebben aan het einde van {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR} STR_2388 :{BLACK}Om plezier te hebben! STR_2389 :{BLACK}Om de beste {STRINGID} te bouwen! -STR_2390 :{BLACK}Om 10 verschillende typen achtbanen in je park te hebben, elk met een spanningswaarde van minstens 6,00 -STR_2391 :{BLACK}Om minstens {COMMA16} bezoekers in je park te hebben. Je parkwaardering mag geen moment onder de 700 komen! -STR_2392 :{BLACK}Om in één maand minstens {POP16}{POP16}{CURRENCY} aan attractiekaartjes te verdienen -STR_2393 :{BLACK}Om 10 verschillende typen achtbanen in je park te hebben, elk met een lengte van minstens {LENGTH} en een spanningswaarde van minstens 7,00 -STR_2394 :{BLACK}Om alle 5 deels gebouwde achtbanen in je park af te maken, ek met een spanningswaarde van minstens {POP16}{POP16}{COMMA2DP32} -STR_2395 :{BLACK}Om je lening terug te betalen en een parkwaarde van minstens {POP16}{POP16}{CURRENCY} te bereiken -STR_2396 :{BLACK}Om in één maand minstens {POP16}{POP16}{CURRENCY} aan de verkoop van eten, drinken en souvenirs te verdienen +STR_2390 :{BLACK}Om 10 verschillende typen achtbanen in je park te hebben, elk met een spanningswaarde van ten minste 6,00 +STR_2391 :{BLACK}Om ten minste {COMMA16} bezoekers in je park te hebben. Je parkwaardering mag geen moment onder de 700 komen! +STR_2392 :{BLACK}Om in één maand ten minste {POP16}{POP16}{CURRENCY} aan attractiekaartjes te verdienen +STR_2393 :{BLACK}Om 10 verschillende typen achtbanen in je park te hebben, elk met een lengte van ten minste {LENGTH} en een spanningswaarde van ten minste 7,00 +STR_2394 :{BLACK}Om alle 5 deels gebouwde achtbanen in je park af te maken, ek met een spanningswaarde van ten minste {POP16}{POP16}{COMMA2DP32} +STR_2395 :{BLACK}Om je lening terug te betalen en een parkwaarde van ten minste {POP16}{POP16}{CURRENCY} te bereiken +STR_2396 :{BLACK}Om in één maand ten minste {POP16}{POP16}{CURRENCY} aan de verkoop van eten, drinken en souvenirs te verdienen STR_2397 :Geen STR_2398 :Aantal bezoekers op een bepaalde datum STR_2399 :Parkwaarde op een bepaalde datum @@ -2402,11 +2402,11 @@ STR_2400 :Plezier hebben STR_2401 :De beste attractie te bouwen STR_2402 :Tien achtbanen bouwen STR_2403 :Aantal bezoekers in het park -STR_2404 :Maandelijks inkomen van attractiekaartjes +STR_2404 :Maandelijks inkomen uit attractiekaartjes STR_2405 :Tien achtbanen van een bepaalde lengte bouwen STR_2406 :Vijf achtbanen afmaken STR_2407 :Lening terugbetalen en een bepaalde parkwaarde bereiken -STR_2408 :Maandelijks inkomen van voedsel/souvenirs +STR_2408 :Maandelijks inkomen uit etenswaren/souvenirs STR_2409 :{WINDOW_COLOUR_2}Lopende marketingcampagnes STR_2410 :{BLACK}Geen STR_2411 :{WINDOW_COLOUR_2}Beschikbare marketingcampagnes @@ -2512,7 +2512,7 @@ STR_2510 :Toon hoogtemarkeringen op paden STR_2511 :Land aanpassen STR_2512 :Water aanpassen STR_2513 :Decor bouwen -STR_2514 :Voetpaden bouwen +STR_2514 :Voetpaden aanleggen STR_2515 :Nieuwe attractie bouwen STR_2516 :Financiële informatie tonen STR_2517 :Onderzoeksinformatie tonen @@ -2678,37 +2678,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :Alle onderzoeken zijn voltooid +STR_2681 :{MEDIUMFONT}{BLACK}Krijg 5.000 extra geld +STR_2682 :{MEDIUMFONT}{BLACK}Wissel tussen betaalde en gratis entree +STR_2683 :{MEDIUMFONT}{BLACK}Alle bezoekers hebben een maximale tevredenheid +STR_2684 :{MEDIUMFONT}{BLACK}Er arriveert een grote groep bezoekers +STR_2685 :Parameters voor Simplex noise +STR_2686 :Minimum: +STR_2687 :Maximum: +STR_2688 :Basisfrequentie: +STR_2689 :Octaven: +STR_2690 :Kaartgenerator +STR_2691 :{WINDOW_COLOUR_2}Basishoogte: +STR_2692 :{WINDOW_COLOUR_2}Waterniveau: +STR_2693 :{WINDOW_COLOUR_2}Terrein: +STR_2694 :Genereren +STR_2695 :Willekeurig terrein +STR_2696 :Bomen plaatsen STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Automatisch opslaan: +STR_2701 :Elke week +STR_2702 :Elke 2 weken +STR_2703 :Elke maand +STR_2704 :Elke 4 maanden +STR_2705 :Elk jaar +STR_2706 :Nooit +STR_2707 :Open nieuw scherm +STR_2708 :{WINDOW_COLOUR_1}Weet je zeker dat je {STRINGID} wilt vervangen? +STR_2709 :Vervangen +STR_2710 :Kies een bestandsnaam. STR_2711 :; STR_2712 := STR_2713 :, @@ -2716,45 +2716,45 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(één map omhoog) +STR_2719 :(nieuw bestand) +STR_2720 :{UINT16}s +STR_2721 :{UINT16}s +STR_2722 :{UINT16}m {UINT16}s +STR_2723 :{UINT16}m {UINT16}s +STR_2724 :{UINT16}m {UINT16}s +STR_2725 :{UINT16}m {UINT16}s +STR_2726 :{UINT16}m +STR_2727 :{UINT16}m +STR_2728 :{UINT16}h {UINT16}m +STR_2729 :{UINT16}h {UINT16}m +STR_2730 :{UINT16}h {UINT16}m +STR_2731 :{UINT16}h {UINT16}m +STR_2732 :{COMMA16} ft +STR_2733 :{COMMA16} m +STR_2734 :{COMMA16} mph +STR_2735 :{COMMA16} km/h +STR_2736 :{MONTH}, jaar {COMMA16} +STR_2737 :{STRINGID} {MONTH}, jaar {COMMA16} +STR_2738 :Titelschermmuziek: +STR_2739 :Geen +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat niet gevonden +STR_2743 :Kopieer data\css17.dat van je RCT1-installatie naar data\css50.dat in je RCT2-installatie. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? +STR_2749 :Mijn nieuwe scenario +STR_2750 :Alles naar boven verplaatsen +STR_2751 :Alles naar beneden verplaatsen +STR_2752 :Onkruid weg +STR_2753 :Gras maaien +STR_2754 :Bloemen water geven +STR_2755 :Vandalisme repareren +STR_2756 :Afval op paden weghalen STR_2757 :Mooi weer STR_2758 :Regen STR_2759 :Hoogtes op nul @@ -2764,7 +2764,7 @@ STR_2762 :Betalen per rit STR_2763 :??? STR_2764 :Tevreden gasten STR_2765 :Grote groep -STR_2766 :??? +STR_2766 :Win scenario STR_2767 :Weer vastzetten STR_2768 :Weer vrijgeven STR_2769 :Park openen @@ -2774,10 +2774,10 @@ STR_2772 :Hogere spelsnelheid STR_2773 :Venster STR_2774 :Volledig scherm STR_2775 :Volledig scherm (bureaublad) -STR_2776 :Taal +STR_2776 :Taal: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} -STR_2779 :Kijkvenster #{COMMA16} +STR_2779 :Kijkvenster {COMMA16} STR_2780 :Extra kijkvenster STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :SHIFT + @@ -2786,8 +2786,8 @@ STR_2784 :Sneltoets wijzigen STR_2785 :{WINDOW_COLOUR_2}Voer een nieuwe sneltoets in voor:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} STR_2786 :{SMALLFONT}{BLACK}Klik op de beschrijving om een nieuwe sneltoets in te stellen STR_2787 :{WINDOW_COLOUR_2}Parkwaarde: {BLACK}{CURRENCY} -STR_2788 :{WINDOW_COLOUR_2}Gefeliciteerd!{NEWLINE}{BLACK}Je hebt je doel bereikt met een bedrijfswaarde van {CURRENCY}! -STR_2789 :{WINDOW_COLOUR_2}Je hebt je doel niet bereikt! +STR_2788 :{WINDOW_COLOUR_2}Gefeliciteerd!{NEWLINE}{BLACK}Je hebt je doelstelling bereikt met een bedrijfswaarde van {CURRENCY}! +STR_2789 :{WINDOW_COLOUR_2}Je hebt je doelstelling niet bereikt! STR_2790 :Naam invoeren voor scenario-overzicht STR_2791 :Naam invoeren STR_2792 :Voer je naam in voor het scenario-overzicht: @@ -2805,9 +2805,9 @@ STR_2803 :{SMALLFONT}{BLACK}Parkkaart tonen waarop deze bezoekers gemarkeerd STR_2804 :{SMALLFONT}{BLACK}Parkkaart tonen waarop deze werknemers gemarkeerd zijn STR_2805 :{SMALLFONT}{BLACK}Parkkaart tonen STR_2806 :{RED}Bezoekers klagen over de smerige voetpaden in je park{NEWLINE}Controleer waar je klusjesmannen zijn en overweeg om ze beter te organiseren -STR_2807 :{RED}Bezoekers klagen over de hoeveelheid rommel{NEWLINE}Controleer waar je klusjesmannen zijn en overweeg om ze beter te organiseren +STR_2807 :{RED}Bezoekers klagen over de hoeveelheid rommel in je park{NEWLINE}Controleer waar je klusjesmannen zijn en overweeg om ze beter te organiseren STR_2808 :{RED}Bezoekers klagen over het vandalisme in je park{NEWLINE}Controleer waar je bewakers zijn en overweeg om ze beter te organiseren -STR_2809 :{RED}Bezoekers hebben honger en kunnen geen plek vinden om voedsel te kopen +STR_2809 :{RED}Bezoekers hebben honger en kunnen geen plek vinden om eten te kopen STR_2810 :{RED}Bezoekers hebben dorst en kunnen geen plek vinden om drinken te kopen STR_2811 :{RED}Bezoekers klagen omdat ze de toiletten in je park niet kunnen vinden STR_2812 :{RED}Bezoekers raken verdwaald of komen vast te zitten{NEWLINE}Controleer of je de indeling van je voetpaden kunt verbeteren @@ -2978,15 +2978,15 @@ STR_2976 :{SMALLFONT}{BLACK}Met het geselecteerde kleurenschema een onderdeel STR_2977 :Naam werknemer STR_2978 :Voer een nieuwe naam in voor deze werknemer: STR_2979 :Kan de naam van deze werknemer niet veranderen... -STR_2980 :Teveel banieren in dit park +STR_2980 :Teveel lichtkranten in dit park STR_2981 :{RED}Geen toegang - - -STR_2982 :Baniertekst -STR_2983 :Voer een nieuwe tekst in voer deze banier: -STR_2984 :Kan de tekst op deze banier niet veranderen... -STR_2985 :Banier -STR_2986 :{SMALLFONT}{BLACK}Tekst op deze banier aanpassen -STR_2987 :{SMALLFONT}{BLACK}Deze banier gebruiken als bord voor 'geen toegang' voor de bezoekers -STR_2988 :{SMALLFONT}{BLACK}Deze banier verwijderen +STR_2982 :Lichtkranttekst +STR_2983 :Voer een nieuwe tekst in voer deze lichtkrant: +STR_2984 :Kan de tekst op deze lichtkrant niet veranderen... +STR_2985 :Lichtkrant +STR_2986 :{SMALLFONT}{BLACK}Tekst op deze lichtkrant aanpassen +STR_2987 :{SMALLFONT}{BLACK}Deze lichtkrant gebruiken als bord voor 'geen toegang' voor de bezoekers +STR_2988 :{SMALLFONT}{BLACK}Deze lichtkrant verwijderen STR_2989 :{SMALLFONT}{BLACK}Hoofdkleur selecteren STR_2990 :{SMALLFONT}{BLACK}Tekstkleur selecteren STR_2991 :Bord @@ -3060,7 +3060,7 @@ STR_3058 :Stenen muren STR_3059 :Heggen STR_3060 :Blokken ijs STR_3061 :Houten schuttingen -STR_3062 :{SMALLFONT}{BLACK}Standard achtbaanspoor +STR_3062 :{SMALLFONT}{BLACK}Standaard achtbaanspoor STR_3063 :{SMALLFONT}{BLACK}Watergedeelte (spoor onder water) STR_3064 :Eenvoudige parken STR_3065 :Uitdagende parken @@ -3181,7 +3181,7 @@ STR_3179 :Er moet minstens één attractie worden geselecteerd STR_3180 :Ongeldige selectie van objecten STR_3181 :Objectselectie - {STRINGID} STR_3182 :Er moet een parkingang worden geselecteerd -STR_3183 :Er moet een watertyoe worden geselecteerd +STR_3183 :Er moet een watertype worden geselecteerd STR_3184 :Attracties/voertuigen STR_3185 :Klein decor STR_3186 :Groot decor @@ -3203,7 +3203,7 @@ STR_3201 :Objectselectie STR_3202 :Landschap bewerken STR_3203 :Uitvindingen instellen STR_3204 :Opties selecteren -STR_3205 :Doel selecteren +STR_3205 :Doelstelling selecteren STR_3206 :Scenario opslaan STR_3207 :Achtbaanontwerper STR_3208 :Baanontwerpbeheer @@ -3239,7 +3239,7 @@ STR_3237 :{SMALLFONT}{BLACK}Toon parkopties STR_3238 :Zonder geld STR_3239 :{SMALLFONT}{BLACK}Schakel geld compleet uit, zodat het park geen financiële beperkingen heeft STR_3240 :{WINDOW_COLOUR_2}Startsaldo: -STR_3241 :{WINDOW_COLOUR_2}Startlening +STR_3241 :{WINDOW_COLOUR_2}Startlening: STR_3242 :{WINDOW_COLOUR_2}Maximale lening: STR_3243 :{WINDOW_COLOUR_2}Jaarlijkse rente: STR_3244 :Marketingcampagnes niet toestaan @@ -3280,12 +3280,12 @@ STR_3278 :{WINDOW_COLOUR_2}Prijs bouwrechten: STR_3279 :Gratis entree / Per rit betalen STR_3280 :Betaalde toegang / Attracties gratis STR_3281 :{WINDOW_COLOUR_2}Entreeprijs: -STR_3282 :{SMALLFONT}{BLACK}Doel en parknaam selecteren +STR_3282 :{SMALLFONT}{BLACK}Doelstelling en parknaam selecteren STR_3283 :{SMALLFONT}{BLACK}Beschermde attracties selecteren STR_3284 :Doelselectie STR_3285 :Beschermde attracties -STR_3286 :{SMALLFONT}{BLACK}Selecteer doel voor dit scenario -STR_3287 :{WINDOW_COLOUR_2}Doel: +STR_3286 :{SMALLFONT}{BLACK}Selecteer doelstelling voor dit scenario +STR_3287 :{WINDOW_COLOUR_2}Doelstelling: STR_3288 :{SMALLFONT}{BLACK}Selecteer klimaat: STR_3289 :{WINDOW_COLOUR_2}Klimaat: STR_3290 :Koel en nat @@ -3299,7 +3299,7 @@ STR_3297 :{SMALLFONT}{BLACK}Details van dit park/scenario aanpassen STR_3298 :{WINDOW_COLOUR_2}Parknaam: {BLACK}{STRINGID} STR_3299 :{WINDOW_COLOUR_2}Parkdetails: STR_3300 :{WINDOW_COLOUR_2}Scenarionaam: {BLACK}{STRINGID} -STR_3301 :{WINDOW_COLOUR_2}Datum doel: +STR_3301 :{WINDOW_COLOUR_2}Datum doelstelling: STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} STR_3303 :{WINDOW_COLOUR_2}Aantal bezoekers: STR_3304 :{WINDOW_COLOUR_2}Parkwaarde: @@ -3320,7 +3320,7 @@ STR_3318 :{SMALLFONT}{BLACK}Selecteer in welke groep dit scenario moet versch STR_3319 :{WINDOW_COLOUR_2}Scenariogroep: STR_3320 :Kan scenariobestand niet opslaan... STR_3321 :Nieuwe objecten successvol geïnstalleerd -STR_3322 :{WINDOW_COLOUR_2}Doel: {BLACK}{STRINGID} +STR_3322 :{WINDOW_COLOUR_2}Doelstelling: {BLACK}{STRINGID} STR_3323 :Ontbrekende objectdata, ID: STR_3324 :Vereist uitbreidingspakket: STR_3325 :Vereist een uitbreidingspakket @@ -3329,8 +3329,8 @@ STR_3327 :Startpositie voor bezoekers niet aangegeven STR_3328 :Kan niet verder naar volgende stap... STR_3329 :Parkingang nog niet gebouwd STR_3330 :Park moet land bezitten -STR_3331 :Pad van de parkingang naar de rand van de kaart is incompleet of te complex; het pad mag maar één blok breed zijn en moet zo min mogelijk kruisingen en bochten bevatten -STR_3332 :Parkingang staan achterstevoren of heeft geen pad naar de rand van de kaart +STR_3331 :Pad van de parkingang naar de rand van de kaart is incompleet of te complex; het pad mag maar één tegel breed zijn en moet zo min mogelijk kruisingen en bochten bevatten +STR_3332 :Parkingang staat achterstevoren of heeft geen pad naar de rand van de kaart STR_3333 :Plug-inobjecten meeleveren in opgeslagen spellen STR_3334 :{SMALLFONT}{BLACK}Selecteer of toegevoegde (niet-standaard) objecten in opgeslagen spellen en scenario's moeten worden meegeleverd, zodat ze geopend kunnen worden door iemand die deze objecten nog niet heeft STR_3335 :Achtbaanontwerper - Attractietypes en -voertuigen selecteren @@ -3360,7 +3360,7 @@ STR_3358 :Kan het baanontwerp niet verwijderen... STR_3359 :{BLACK}Geen baanontwerpen van dit type STR_3360 :Waarschuwing! STR_3361 :Te veel baanontwerpen van dit type; sommige staan niet in de lijst -STR_3362 :Mixing via softwarebuffer forceren +STR_3362 :Mixen via softwarebuffer forceren STR_3363 :{SMALLFONT}{BLACK}Selecteer deze optie om de prestaties te verbeteren als het spel vertraagt bij het afspelen van geluiden of als er ruis hoorbaar is STR_3364 :Meer opties STR_3365 :{SMALLFONT}{BLACK}Maakt naast selectie van decorgroepen ook selectie van losse items mogelijk @@ -3368,9 +3368,9 @@ STR_3366 :{BLACK}= Attractie STR_3367 :{BLACK}= Eetkraampje STR_3368 :{BLACK}= Drankkraampje STR_3369 :{BLACK}= Souvenirkraampje -STR_3370 :{BLACK}= Infokiosk +STR_3370 :{BLACK}= Informatiekiosk STR_3371 :{BLACK}= Eerste hulp -STR_3372 :{BLACK}= PIN +STR_3372 :{BLACK}= Geldautomaat STR_3373 :{BLACK}= Toilet STR_3374 :Waarschuwing: teveel objecten geselecteerd! STR_3375 :Niet alle objecten in deze decorgroep kunnen worden geselecteerd @@ -3379,13 +3379,13 @@ STR_3377 :{SMALLFONT}{BLACK}Bestand met nieuw baanontwerp installeren STR_3378 :Installeren STR_3379 :Annuleren STR_3380 :Kan dit baanontwerp niet installeren... -STR_3381 :Bestand is niet compatible of bevat ongeldige gegevens +STR_3381 :Bestand is niet compatibel of bevat ongeldige gegevens STR_3382 :Kopiëren van bestand mislukt STR_3383 :Selecteer nieuwe naam voor dit baanontwerp STR_3384 :Er bestaat al een baanontwerp met deze naam; verzin een andere naam voor dit ontwerp: STR_3385 :Tutorial voor beginners -STR_3386 :Toturial voor eigen ontwerpen -STR_3387 :Toturial voor achtbanen bouwen +STR_3386 :Tutorial voor eigen ontwerpen +STR_3387 :Tutorial voor achtbanen bouwen STR_3388 :Kan niet naar de geselecteerde modus overschakelen STR_3389 :Kan extra decorstukken niet selecteren... STR_3390 :Te veel items geselecteerd @@ -3397,14 +3397,14 @@ STR_3395 :{SMALLFONT}{BLACK}Dingen bouwen vanaf deze hoogte is een beetje las STR_3396 :{SMALLFONT}{BLACK}Laten we een simpele attractie bouwen om met dit park te beginnen... STR_3397 :{SMALLFONT}{BLACK}Het witte 'spookplaatje' laat zien waar de attractie zal worden gebouwd. Beweeg de muis er naar toe en klik om het te bouwen... STR_3398 :{SMALLFONT}{BLACK}Attracties hebben een ingang en een uitgang nodig. Beweeg de muis naar een tegeltje aan de rand van de attractie en klik om de ingang te bouwen. Klik nog een keer ergens om de uitgang te bouwen... -STR_3399 :{SMALLFONT}{BLACK}We moeten een voetpad bouwen zodat bezoekers onze nieuwe attractie kunnen bereiken... +STR_3399 :{SMALLFONT}{BLACK}We moeten een voetpad aanleggen zodat bezoekers onze nieuwe attractie kunnen bereiken... STR_3400 :{SMALLFONT}{BLACK}Voor het pad naar de ingang gebruiken we een speciaal wachtrij-voetpad... STR_3401 :{SMALLFONT}{BLACK}Voor de uitgang maakt het niet uit welk pad je gebruikt. Een normaal pad is goed... STR_3402 :{SMALLFONT}{BLACK}Oké dan, laten we de attractie openen! Om de attractie te openen klikken we op het knopje met de vlag in het attractievenster en selecteren we 'openen'... STR_3403 :{SMALLFONT}{BLACK}Maar waar zijn de bezoekers?! STR_3404 :{SMALLFONT}{BLACK}Oh, juist - het park is nog gesloten! Laten we ons park openen... STR_3405 :{SMALLFONT}{BLACK}Terwijl we op onze eerste bezoekers wachten kunnen we wat decorstukken neerzetten... -STR_3406 :{SMALLFONT}{BLACK}Dit is ons lege park. We gaan een simpele zelfontworpen attractie bouwen... +STR_3406 :{SMALLFONT}{BLACK}Dit is ons lege park. We gaan een simpele, zelfontworpen attractie bouwen... STR_3407 :{SMALLFONT}{BLACK}Ten eerste hebben we een startpositie nodig... STR_3408 :{SMALLFONT}{BLACK}Het stuk baan dat we net gebouwd hebben is een 'station' en zorgt ervoor dat bezoekers in en uit kunnen stappen... STR_3409 :{SMALLFONT}{BLACK}We verlengen het perron een beetje door nog wat stationsgedeeltes aan te leggen... @@ -3414,7 +3414,7 @@ STR_3412 :{SMALLFONT}{BLACK}De bocht is nog niet gebouwd, maar het witte spoo STR_3413 :{SMALLFONT}{BLACK}Nu willen we een recht stuk bouwen, dus klikken we op het knopje voor 'recht stuk'... STR_3414 :{SMALLFONT}{BLACK}De baan is af, we kunnen nu de ingang en uitgang bouwen... STR_3415 :{SMALLFONT}{BLACK}Laten we testen of onze attractie werkt... -STR_3416 :{SMALLFONT}{BLACK}Terwijl de attractie wordt getest kunnen we een wachtrij en uitgangspad bouwen... +STR_3416 :{SMALLFONT}{BLACK}Terwijl de attractie wordt getest kunnen we een wachtrij en uitgangspad aanleggen... STR_3417 :{SMALLFONT}{BLACK}Goed - laten we het park en onze attractie openen... STR_3418 :{SMALLFONT}{BLACK}Onze nieuwe attractie is niet heel erg spannend; misschien moeten we wat decor toevoegen? STR_3419 :{SMALLFONT}{BLACK}Om decor te bouwen boven ander decor (of midden in de lucht) hou je de SHIFT-toets ingedrukt en beweeg je de muis om de hoogte te bepalen... @@ -3425,13 +3425,13 @@ STR_3423 :{SMALLFONT}{BLACK}Er zijn veel kant-en-klare achtbanen, maar wij ga STR_3424 :{SMALLFONT}{BLACK}Zo, het station is af. Nu hebben we een liftheuvel nodig... STR_3425 :{SMALLFONT}{BLACK}Achtbaankarretjes zijn niet aangedreven, dus is een 'kettinglift' nodig om ze eerst een heuvel op te trekken... STR_3426 :{SMALLFONT}{BLACK}Goed, de liftheuvel is klaar - nu de eerste afdaling... -STR_3427 :{SMALLFONT}{BLACK}Die bochten zijn een slecht idee; de passagiers zullen naar de zijkanten geslingerd worden door de G-kracht wanneer de trein er doorheen raast... +STR_3427 :{SMALLFONT}{BLACK}Die bochten zijn een slecht idee; de passagiers zullen naar de zijkanten geslingerd worden door de zijwaartse G-krachten wanneer de trein er doorheen raast... STR_3428 :{SMALLFONT}{BLACK}De bochten een banking geven (schuinleggen) zal de rit prettiger maken, aangezien de passagiers in hun stoelen geduwd zullen worden in plaats van naar de zijkanten... STR_3429 :{SMALLFONT}{BLACK}Dit gaat niet werken! Kijk naar de hoogtemarkeringen: de tweede heuvel is hoger dan de liftheuvel... STR_3430 :{SMALLFONT}{BLACK}Om ervoor te zorgen dat de trein terug naar het station komt, moet elke heuvel iets lager zijn dan de heuvel daarvoor... STR_3431 :{SMALLFONT}{BLACK}Dat ziet er beter uit! Onze trein zou het nu moeten halen! Laten we wat meer bochtige stukjes toevoegen... STR_3432 :{SMALLFONT}{BLACK}We moeten de trein afremmen voordat we de laatste bocht en het station inkomen, dus laten we wat remmen toevoegen... -STR_3433 :{SMALLFONT}{BLACK}En tenslotte voegen we 'blokremmen' toe. Die zorgen ervoor dat twee treinen tegelijk (en veilig) op de baan kunnen zitten... +STR_3433 :{SMALLFONT}{BLACK}En tenslotte voegen we 'blokremmen' toe. Die zorgen ervoor dat twee treinen tegelijk (en veilig) op de baan kunnen rijden... STR_3434 :{SMALLFONT}{BLACK}Laten we kijken of onze achtbaan werkt! STR_3435 :{SMALLFONT}{BLACK}Fantastisch, hij werkt! Laten we wat voetpaden aanleggen, zodat bezoekers bij onze nieuwe achtbaan kunnen komen... STR_3436 :{SMALLFONT}{BLACK}Terwijl we wachten op onze eerste bezoekers, kunnen we onze achtbaan een beetje aanpassen... @@ -3445,3 +3445,232 @@ STR_3443 :Pagina 4 STR_3444 :Pagina 5 STR_3445 :Werkgebied instellen STR_3446 :Werkgebied wissen + +#Start van OpenRCT2-indices +STR_5120 :'Financiën'-knop in de werkbalk tonen +STR_5121 :'Onderzoek'-knop in de werkbalk tonen +STR_5122 :Alle voertuigen met hetzelfde baan- of attractietype tonen +STR_5123 :Attr. vernieuwen +STR_5124 :Six Flags weg +STR_5125 :Afbreekbaar maken +STR_5126 :Willekeurige titelmuziek +STR_5127 :{SMALLFONT}{BLACK}Landtype i.p.v. landhoogte aanpassen bij slepen +STR_5128 :Selectiegrootte +STR_5129 :Voer een selectiegrootte in tussen {COMMA16} en {COMMA16} +STR_5130 :Kaartgrootte +STR_5131 :Voer een kaartgrootte in tussen {COMMA16} en {COMMA16} +STR_5132 :Alle attr. repareren +STR_5133 :{SMALLFONT}{BLACK}Een kleiner gebied landrechten aanpassen +STR_5134 :{SMALLFONT}{BLACK}Een groter gebied landrechten aanpassen +STR_5135 :{SMALLFONT}{BLACK}Land en bouwrechten kopen +STR_5136 :Landrechten +STR_5137 :Kettingliften en lanceringen{NEWLINE}kunnen tot {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Defecte remmen onmogelijk maken +STR_5141 :Attractiedefecten uitschakelen +STR_5142 :Normaal +STR_5143 :Vlot +STR_5144 :Hard +STR_5145 :Turbo +STR_5146 :Nitro +STR_5147 :'Cheats'-knop in de werkbalk tonen +STR_5148 :{SMALLFONT}{BLACK}Spelsnelheid veranderen +STR_5149 :{SMALLFONT}{BLACK}Het cheatsvenster openen +STR_5150 :Debugging-hulpmiddelen inschakelen +#Scheidingsteken voor duizendtallen +STR_5151 :. +#Scheidingsteken voor decimalen +STR_5152 :, +STR_5153 :Thema's +STR_5154 :Weergave uitgevoerd door hardware +STR_5155 :Testen van onvoltooide banen toestaan +STR_5156 :{SMALLFONT}{BLACK}Maakt het mogelijk om de meeste attractietypes te testen, zelfs als de baan niet voltooid is. Werkt niet als de baan gebruik maakt van een blokremmodus. +STR_5157 :Alle prijzen ontgrendelen +STR_5158 :Terug naar het hoofdmenu +STR_5159 :OpenRCT2 afsluiten +STR_5160 :{MONTH} {STRINGID}, jaar {COMMA16} +STR_5161 :Datumnotatie: +STR_5162 :Dag/maand/jaar +STR_5163 :Maand/dag/jaar +STR_5164 :Twitch-kanaalnaam +STR_5165 :Bezoekers namen van volgers geven +STR_5166 :Geeft bezoekers namen van gebruikers die het Twitch-kanaal volgen. +STR_5167 :Bezoekers met Twitch-volgersnamen volgen in berichtengebied +STR_5168 :Zet het bezoekersvolgsysteem aan voor bezoekers die naar Twitch-volgers zijn genoemd. +STR_5169 :Bezoekers namen van gebruikers in de Twitch-chat geven +STR_5170 :Geeft bezoekers namen van gebruikers in de Twitch-chat. +STR_5171 :Bezoekers met Twitch-chatnamen volgen in berichtengebied +STR_5172 :Zet het bezoekersvolgsysteem aan voor bezoekers die naar Twitch-chatters zijn genoemd. +STR_5173 :Twitch-chat als nieuws weergeven +STR_5174 :Zal chatberichten op Twitch die beginnen met !news in het berichtengebied tonen. +STR_5175 :Voer de naam van je Twitch-kanaal in +STR_5176 :Twitch-integratie inschakelen +STR_5177 :Schermmodus: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Basishoogte +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Waterniveau +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Financiën +STR_5188 :Nieuwe advertentiecampagne +STR_5189 :Onderzoek +STR_5190 :Kaart +STR_5191 :Kijkvenster +STR_5192 :Recente berichten +STR_5193 :Land +STR_5194 :Water +STR_5195 :Decor verwijderen +STR_5196 :Landrechten +STR_5197 :Decor +STR_5198 :Voetpaden +STR_5199 :Bouwvenster attracties +STR_5200 :Baanontwerp plaatsen +STR_5201 :Nieuwe attractie +STR_5202 :Selectie baanontwerp +STR_5203 :Attractie +STR_5204 :Attractielijst +STR_5205 :Bezoeker +STR_5206 :Bezoekerslijst +STR_5207 :Werknemer +STR_5208 :Werknemerslijst +STR_5209 :Lichtkrant +STR_5210 :Objectselectie +STR_5211 :Uitvindingenlijst +STR_5212 :Scenario-opties +STR_5213 :Doelstellingsopties +STR_5214 :Kaartgenerator +STR_5215 :Baanontwerpbeheer +STR_5216 :Lijst baanontwerpbeheer +STR_5217 :Cheats +STR_5218 :Thema's +STR_5219 :Opties +STR_5220 :Sneltoetsen +STR_5221 :Sneltoets aanpassen +STR_5222 :Laden/opslaan +STR_5223 :Opslagbevestiging +STR_5224 :Afbraakbevestiging +STR_5225 :Ontslagbevestiging +STR_5226 :Bevestiging verwijderen baanontwerp +STR_5227 :Overschrijvingsbevestiging +STR_5228 :{SMALLFONT}{BLACK}Hoofdinterface +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Hulpmiddelen +STR_5231 :{SMALLFONT}{BLACK}Attracties en bezoekers +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Overigs +STR_5234 :{SMALLFONT}{BLACK}Dialoogvensters +STR_5235 :{SMALLFONT}{BLACK}Instellingen +STR_5236 :Venster: +STR_5237 :Palet: +STR_5238 :Huidig thema: +STR_5239 :Kopiëren +STR_5240 :Voer een naam in voor dit thema +STR_5241 :Kan dit thema niet wijzigen +STR_5242 :Themanaam bestaat al +STR_5243 :Er zijn ongeldige tekens gebruikt +STR_5244 :Thema's +STR_5245 :Bovenste werkbalk +STR_5246 :Onderste werkbalk +STR_5247 :Onderste werkbalk baanontwerper/beheerder +STR_5248 :Onderste werkbalk scenariobewerker +STR_5249 :Menuknoppen titelsherm +STR_5250 :Afsluitknop titelscherm +STR_5251 :Optiesknop titelscherm +STR_5252 :Scenarioselectie titelscherm +STR_5253 :Parkinformatie +STR_5254 :Misselijk maken +STR_5255 :{MEDIUMFONT}{BLACK}Zal alle bezoekers misselijk maken +STR_5256 :Een nieuw thema aanmaken om wijzigingen aan te brengen +STR_5257 :{SMALLFONT}{BLACK}Een nieuw thema aanmaken dat is gebaseerd op het huidige +STR_5258 :{SMALLFONT}{BLACK}Het huidige thema verwijderen +STR_5259 :{SMALLFONT}{BLACK}Het huidige thema hernoemen +STR_5260 :Enorm screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Overig +STR_5265 :{SMALLFONT}{BLACK}Selecteer uit welke bronnen objecten zichtbaar zijn +STR_5266 :{SMALLFONT}{BLACK}Weergave +STR_5267 :{SMALLFONT}{BLACK}Landinstellingen +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Bediening +STR_5270 :{SMALLFONT}{BLACK}Overig +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Klein decor +STR_5273 :{SMALLFONT}{BLACK}Groot decor +STR_5274 :{SMALLFONT}{BLACK}Voetpaden +STR_5275 :Naar objecten zoeken +STR_5276 :Voer de naam van een op te zoeken object in: +STR_5277 :Wissen +STR_5278 :Zandbakmodus +STR_5279 :Zandbakmodus uit +STR_5280 :{SMALLFONT}{BLACK}Maakt het aanpassen van landeigendom via het Kaart-venster en andere zaken die normaal gesproken alleen in de Scenariobewerker beschikbaar zijn mogelijk +STR_5281 :{SMALLFONT}{BLACK}Features +STR_5282 :Attracties openen/sluiten via RCT1-stoplichten +STR_5283 :Park openen/sluiten via RCT1-stoplichten +STR_5284 :Scenarioselectie-lettertype in RCT1-stijl +STR_5285 :KABOEM! +STR_5286 :{MEDIUMFONT}{BLACK}Laat alle gasten exploderen +STR_5287 :Attractie is al defect +STR_5288 :Attractie is gesloten +STR_5289 :Deze attractie kan niet defect raken +STR_5290 :Attractie repareren +STR_5291 :Kan geen defect forceren +STR_5292 :{SMALLFONT}{BLACK}Defect forceren +STR_5293 :{SMALLFONT}{BLACK}Attractie sluiten +STR_5294 :{SMALLFONT}{BLACK}Attractie testen +STR_5295 :{SMALLFONT}{BLACK}Attractie openen +STR_5296 :{SMALLFONT}{BLACK}Park sluiten +STR_5297 :{SMALLFONT}{BLACK}Park openen +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}Snel ontslaan +STR_5301 :{MEDIUMFONT}{BLACK}Wist je lening +STR_5302 :Lening afbetalen +STR_5303 :Bouwen in pauzemodus toestaan +STR_5304 :Titelshow: +STR_5305 :RollerCoaster Tycoon 1 +STR_5306 :RollerCoaster Tycoon 1 (AA) +STR_5307 :RollerCoaster Tycoon 1 (AA + LL) +STR_5308 :RollerCoaster Tycoon 2 +STR_5309 :OpenRCT2 +STR_5310 :Willekeurige +STR_5311 :{SMALLFONT}{BLACK}Debugginghulpmiddelen +STR_5312 :Console tonen +STR_5313 :Vakinspecteur tonen +STR_5314 :Vakinspecteur +STR_5315 :Gras +STR_5316 :Zand +STR_5317 :Aarde +STR_5318 :Steen +STR_5319 :Buitenaards +STR_5320 :Schaakbord +STR_5321 :Kluiten gras +STR_5322 :IJs +STR_5323 :Raster (rood) +STR_5324 :Raster (geel) +STR_5325 :Raster (blauw) +STR_5326 :Raster (groen) +STR_5327 :Raster (donker) +STR_5328 :Raster (licht) +STR_5329 :Schaakbord (omgekeerd) +STR_5330 :Ondergronds zicht +STR_5331 :Steen +STR_5332 :Houten palen (rood) +STR_5333 :Houten palen (zwart) +STR_5334 :IJs +STR_5335 :Attractie-ingang +STR_5336 :Attractie-uitgang +STR_5337 :Parkingang +STR_5338 :Elementtype +STR_5339 :Hoogte onderkant +STR_5340 :Hoogte bovenkant +STR_5341 :Eigenschappen +STR_5342 :Kies een vakje op de kaart +STR_5343 :Werknemers automatisch plaatsen +STR_5344 :Wijzigingsoverzicht diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 168ec8a5b2..379cf6b46c 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -3,97 +3,97 @@ # Use # at the beginning of a line to leave a comment. STR_0000 : STR_0001 :{STRINGID} {COMMA16} -STR_0002 :Ride -STR_0003 :Ride +STR_0002 :Spiral Roller Coaster +STR_0003 :Stand-up Roller Coaster STR_0004 :Suspended Swinging Coaster -STR_0005 :Ride +STR_0005 :Inverted Roller Coaster STR_0006 :Junior Roller Coaster STR_0007 :Miniature Railway STR_0008 :Monorail STR_0009 :Mini Suspended Coaster -STR_0010 :Ride -STR_0011 :Ride -STR_0012 :Ride +STR_0010 :Boat Ride +STR_0011 :Wooden Wild Mouse +STR_0012 :Steeplechase STR_0013 :Car Ride -STR_0014 :Ride -STR_0015 :Ride -STR_0016 :Ride +STR_0014 :Launched Freefall +STR_0015 :Bobsleigh Coaster +STR_0016 :Observation Tower STR_0017 :Looping Roller Coaster -STR_0018 :Ride -STR_0019 :Ride +STR_0018 :Dinghy Slide +STR_0019 :Mine Train Coaster STR_0020 :Chairlift -STR_0021 :Ride -STR_0022 :Ride -STR_0023 :Ride -STR_0024 :Ride -STR_0025 :Ride -STR_0026 :Ride -STR_0027 :Ride -STR_0028 :Ride -STR_0029 :Ride -STR_0030 :Stall -STR_0031 :Stall -STR_0032 :Stall -STR_0033 :Stall -STR_0034 :Stall -STR_0035 :Ride -STR_0036 :Stall -STR_0037 :Kiosk -STR_0038 :Restroom -STR_0039 :Ride -STR_0040 :Ride -STR_0041 :Ride -STR_0042 :Ride -STR_0043 :Ride +STR_0021 :Corkscrew Roller Coaster +STR_0022 :Maze +STR_0023 :Spiral Slide +STR_0024 :Go Karts +STR_0025 :Log Flume +STR_0026 :River Rapids +STR_0027 :Dodgems +STR_0028 :Pirate Ship +STR_0029 :Swinging Inverter Ship +STR_0030 :Food Stall +STR_0031 :Unknown Stall (1D) +STR_0032 :Drink Stall +STR_0033 :Unknown Stall (1F) +STR_0034 :Shop +STR_0035 :Merry-Go-Round +STR_0036 :Unknown Stall (22) +STR_0037 :Information Kiosk +STR_0038 :Toilets +STR_0039 :Ferris Wheel +STR_0040 :Motion Simulator +STR_0041 :3D Cinema +STR_0042 :Top Spin +STR_0043 :Space Rings STR_0044 :Reverse Freefall Coaster STR_0045 :Lift -STR_0046 :Ride -STR_0047 :Ride -STR_0048 :Ride -STR_0049 :Ride -STR_0050 :Ride -STR_0051 :Ride -STR_0052 :Ride -STR_0053 :Hyper-Twister Roller Coaster +STR_0046 :Vertical Drop Roller Coaster +STR_0047 :Cash Machine +STR_0048 :Twist +STR_0049 :Haunted House +STR_0050 :First Aid Room +STR_0051 :Circus Show +STR_0052 :Ghost Train +STR_0053 :Twister Roller Coaster STR_0054 :Wooden Roller Coaster STR_0055 :Side-Friction Roller Coaster STR_0056 :Wild Mouse STR_0057 :Multi-Dimension Roller Coaster -STR_0058 :Ride -STR_0059 :Aerial Inverted Roller Coaster -STR_0060 :Ride -STR_0061 :Ride -STR_0062 :Ride -STR_0063 :Ride -STR_0064 :Ride +STR_0058 :Unknown Ride (38) +STR_0059 :Flying Roller Coaster +STR_0060 :Unknown Ride (3A) +STR_0061 :Virginia Reel +STR_0062 :Splash Boats +STR_0063 :Mini Helicopters +STR_0064 :Lay-down Roller Coaster STR_0065 :Suspended Monorail -STR_0066 :Ride -STR_0067 :Ride +STR_0066 :Unknown Ride (40) +STR_0067 :Reverser Roller Coaster STR_0068 :Heartline Twister Coaster -STR_0069 :Ride -STR_0070 :Ride -STR_0071 :Ride -STR_0072 :Ride -STR_0073 :Ride -STR_0074 :Ride -STR_0075 :Ride +STR_0069 :Mini Golf +STR_0070 :Giga Coaster +STR_0071 :Roto-Drop +STR_0072 :Flying Saucers +STR_0073 :Crooked House +STR_0074 :Monorail Cycles +STR_0075 :Compact Inverted Coaster STR_0076 :Water Coaster -STR_0077 :Ride -STR_0078 :Ride -STR_0079 :Ride -STR_0080 :Ride -STR_0081 :Ride -STR_0082 :Ride -STR_0083 :Ride -STR_0084 :Ride -STR_0085 :Ride -STR_0086 :Ride -STR_0087 :Ride -STR_0088 :Ride +STR_0077 :Air Powered Vertical Coaster +STR_0078 :Inverted Hairpin Coaster +STR_0079 :Magic Carpet +STR_0080 :Submarine Ride +STR_0081 :River Rafts +STR_0082 :Unknown Ride (50) +STR_0083 :Enterprise +STR_0084 :Unknown Ride (52) +STR_0085 :Unknown Ride (53) +STR_0086 :Unknown Ride (54) +STR_0087 :Unknown Ride (55) +STR_0088 :Inverted Impulse Coaster STR_0089 :Mini Roller Coaster -STR_0090 :Ride -STR_0091 :Ride -STR_0092 :Ride +STR_0090 :Mine Ride +STR_0091 :Unknown Ride (59) +STR_0092 :LIM Launched Roller Coaster STR_0093 : STR_0094 : STR_0095 : @@ -977,7 +977,7 @@ STR_0972 :Cancel STR_0973 :OK STR_0974 :Rides STR_0975 :Shops and Stalls -STR_0976 :Restrooms and Information Kiosks +STR_0976 :Toilets and Information Kiosks STR_0977 :New Transport Rides STR_0978 :New Gentle Rides STR_0979 :New Roller Coasters @@ -1065,7 +1065,7 @@ STR_1060 :Invalid ride/attraction name STR_1061 :Normal mode STR_1062 :Continuous circuit mode STR_1063 :Reverse-Incline launched shuttle mode -STR_1064 :Powered launch +STR_1064 :Powered launch (passing station) STR_1065 :Shuttle mode STR_1066 :Boat hire mode STR_1067 :Upward launch @@ -1097,7 +1097,7 @@ STR_1092 :Downward launch STR_1093 :Crooked house mode STR_1094 :Freefall drop mode STR_1095 :Continuous circuit block sectioned mode -STR_1096 :Powered launch +STR_1096 :Powered launch (without passing station) STR_1097 :Powered launch block sectioned mode STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} @@ -1526,9 +1526,9 @@ STR_1521 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really STR_1522 :{SMALLFONT}{OPENQUOTES}This umbrella from {STRINGID} is really good value{ENDQUOTES} STR_1523 :{SMALLFONT}{OPENQUOTES}This drink from {STRINGID} is really good value{ENDQUOTES} STR_1524 :{SMALLFONT}{OPENQUOTES}This burger from {STRINGID} is really good value{ENDQUOTES} -STR_1525 :{SMALLFONT}{OPENQUOTES}These fries from {STRINGID} are really good value{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}These chips from {STRINGID} are really good value{ENDQUOTES} STR_1526 :{SMALLFONT}{OPENQUOTES}This ice cream from {STRINGID} is really good value{ENDQUOTES} -STR_1527 :{SMALLFONT}{OPENQUOTES}This cotton candy from {STRINGID} is really good value{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}This candyfloss from {STRINGID} is really good value{ENDQUOTES} STR_1528 : STR_1529 : STR_1530 : @@ -1538,7 +1538,7 @@ STR_1533 :{SMALLFONT}{OPENQUOTES}This popcorn from {STRINGID} is really good STR_1534 :{SMALLFONT}{OPENQUOTES}This hot dog from {STRINGID} is really good value{ENDQUOTES} STR_1535 :{SMALLFONT}{OPENQUOTES}This tentacle from {STRINGID} is really good value{ENDQUOTES} STR_1536 :{SMALLFONT}{OPENQUOTES}This hat from {STRINGID} is really good value{ENDQUOTES} -STR_1537 :{SMALLFONT}{OPENQUOTES}This candy apple from {STRINGID} is really good value{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}This toffee apple from {STRINGID} is really good value{ENDQUOTES} STR_1538 :{SMALLFONT}{OPENQUOTES}This T-shirt from {STRINGID} is really good value{ENDQUOTES} STR_1539 :{SMALLFONT}{OPENQUOTES}This doughnut from {STRINGID} is really good value{ENDQUOTES} STR_1540 :{SMALLFONT}{OPENQUOTES}This coffee from {STRINGID} is really good value{ENDQUOTES} @@ -1560,9 +1560,9 @@ STR_1555 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride phot STR_1556 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an umbrella from {STRINGID}{ENDQUOTES} STR_1557 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a drink from {STRINGID}{ENDQUOTES} STR_1558 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a burger from {STRINGID}{ENDQUOTES} -STR_1559 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fries from {STRINGID}{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for chips from {STRINGID}{ENDQUOTES} STR_1560 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an ice cream from {STRINGID}{ENDQUOTES} -STR_1561 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for cotton candy from {STRINGID}{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for candyfloss from {STRINGID}{ENDQUOTES} STR_1562 : STR_1563 : STR_1564 : @@ -1572,7 +1572,7 @@ STR_1567 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for popcorn from {S STR_1568 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a hot dog from {STRINGID}{ENDQUOTES} STR_1569 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for tentacle from {STRINGID}{ENDQUOTES} STR_1570 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a hat from {STRINGID}{ENDQUOTES} -STR_1571 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a candy apple from {STRINGID}{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a toffee apple from {STRINGID}{ENDQUOTES} STR_1572 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a T-shirt from {STRINGID}{ENDQUOTES} STR_1573 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a doughnut from {STRINGID}{ENDQUOTES} STR_1574 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for coffee from {STRINGID}{ENDQUOTES} @@ -1778,7 +1778,7 @@ STR_1773 :Only one on-ride photo section allowed per ride STR_1774 :Only one cable lift hill allowed per ride STR_1775 :Off STR_1776 :On -STR_1777 :{WINDOW_COLOUR_2}Music: +STR_1777 :{WINDOW_COLOUR_2}Music STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigre costume @@ -1842,7 +1842,7 @@ STR_1837 :Satisfaction: Unknown STR_1838 :Satisfaction: {COMMA16}% STR_1839 :Reliability: {COMMA16}% STR_1840 :Down-time: {COMMA16}% -STR_1841 :Profit: {CURRENCY} per hour +STR_1841 :Profit: {CURRENCY2DP} per hour STR_1842 :Favourite of: {COMMA16} guest STR_1843 :Favourite of: {COMMA16} guests STR_1844 :{SMALLFONT}{BLACK}Select information type to show in ride/attraction list @@ -1859,7 +1859,7 @@ STR_1854 :{WINDOW_COLOUR_2}Built: {BLACK}Last Year STR_1855 :{WINDOW_COLOUR_2}Built: {BLACK}{COMMA16} Years Ago STR_1856 :{WINDOW_COLOUR_2}Profit per item sold: {BLACK}{CURRENCY2DP} STR_1857 :{WINDOW_COLOUR_2}Loss per item sold: {BLACK}{CURRENCY2DP} -STR_1858 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} per month +STR_1858 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY2DP} per month STR_1859 :Handymen STR_1860 :Mechanics STR_1861 :Security Guards @@ -1874,8 +1874,8 @@ STR_1869 :{WINDOW_COLOUR_2}Number of rotations: STR_1870 :{SMALLFONT}{BLACK}Number of complete rotations STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1872 :{COMMA16} -STR_1873 :{WINDOW_COLOUR_2}Income: {BLACK}{CURRENCY} per hour -STR_1874 :{WINDOW_COLOUR_2}Profit: {BLACK}{CURRENCY} per hour +STR_1873 :{WINDOW_COLOUR_2}Income: {BLACK}{CURRENCY2DP} per hour +STR_1874 :{WINDOW_COLOUR_2}Profit: {BLACK}{CURRENCY2DP} per hour STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Inspect Rides STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Fix Rides @@ -1968,9 +1968,9 @@ STR_1963 :{WINDOW_COLOUR_2}On-Ride Photo price: STR_1964 :{WINDOW_COLOUR_2}Umbrella price: STR_1965 :{WINDOW_COLOUR_2}Drink price: STR_1966 :{WINDOW_COLOUR_2}Burger price: -STR_1967 :{WINDOW_COLOUR_2}Fries price: +STR_1967 :{WINDOW_COLOUR_2}Chips price: STR_1968 :{WINDOW_COLOUR_2}Ice Cream price: -STR_1969 :{WINDOW_COLOUR_2}Cotton Candy price: +STR_1969 :{WINDOW_COLOUR_2}Candyfloss price: STR_1970 :{WINDOW_COLOUR_2} STR_1971 :{WINDOW_COLOUR_2} STR_1972 :{WINDOW_COLOUR_2} @@ -1980,7 +1980,7 @@ STR_1975 :{WINDOW_COLOUR_2}Popcorn price: STR_1976 :{WINDOW_COLOUR_2}Hot Dog price: STR_1977 :{WINDOW_COLOUR_2}Tentacle price: STR_1978 :{WINDOW_COLOUR_2}Hat price: -STR_1979 :{WINDOW_COLOUR_2}Candy Apple price: +STR_1979 :{WINDOW_COLOUR_2}Toffee Apple price: STR_1980 :{WINDOW_COLOUR_2}T-Shirt price: STR_1981 :{WINDOW_COLOUR_2}Doughnut price: STR_1982 :{WINDOW_COLOUR_2}Coffee price: @@ -1996,9 +1996,9 @@ STR_1991 :On-Ride Photo STR_1992 :Umbrella STR_1993 :Drink STR_1994 :Burger -STR_1995 :Fries +STR_1995 :Chips STR_1996 :Ice Cream -STR_1997 :Cotton Candy +STR_1997 :Candyfloss STR_1998 :Empty Can STR_1999 :Rubbish STR_2000 :Empty Burger Box @@ -2008,7 +2008,7 @@ STR_2003 :Popcorn STR_2004 :Hot Dog STR_2005 :Tentacle STR_2006 :Hat -STR_2007 :Candy Apple +STR_2007 :Toffee Apple STR_2008 :T-Shirt STR_2009 :Doughnut STR_2010 :Coffee @@ -2024,9 +2024,9 @@ STR_2019 :On-Ride Photos STR_2020 :Umbrellas STR_2021 :Drinks STR_2022 :Burgers -STR_2023 :Fries +STR_2023 :Chips STR_2024 :Ice Creams -STR_2025 :Cotton Candy +STR_2025 :Candyfloss STR_2026 :Empty Cans STR_2027 :Rubbish STR_2028 :Empty Burger Boxes @@ -2036,7 +2036,7 @@ STR_2031 :Popcorn STR_2032 :Hot Dogs STR_2033 :Tentacles STR_2034 :Hats -STR_2035 :Candy Apples +STR_2035 :Toffee Apples STR_2036 :T-Shirts STR_2037 :Doughnuts STR_2038 :Coffees @@ -2052,9 +2052,9 @@ STR_2047 :an On-Ride Photo STR_2048 :an Umbrella STR_2049 :a Drink STR_2050 :a Burger -STR_2051 :some Fries +STR_2051 :some Chips STR_2052 :an Ice Cream -STR_2053 :some Cotton Candy +STR_2053 :some Candyfloss STR_2054 :an Empty Can STR_2055 :some Rubbish STR_2056 :an Empty Burger Box @@ -2064,7 +2064,7 @@ STR_2059 :some Popcorn STR_2060 :a Hot Dog STR_2061 :a Tentacle STR_2062 :a Hat -STR_2063 :a Candy Apple +STR_2063 :a Toffee Apple STR_2064 :a T-Shirt STR_2065 :a Doughnut STR_2066 :a Coffee @@ -2080,9 +2080,9 @@ STR_2075 :On-Ride Photo of {STRINGID} STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Umbrella STR_2077 :Drink STR_2078 :Burger -STR_2079 :Fries +STR_2079 :Chips STR_2080 :Ice Cream -STR_2081 :Cotton Candy +STR_2081 :Candyfloss STR_2082 :Empty Can STR_2083 :Rubbish STR_2084 :Empty Burger Box @@ -2092,7 +2092,7 @@ STR_2087 :Popcorn STR_2088 :Hot Dog STR_2089 :Tentacle STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hat -STR_2091 :Candy Apple +STR_2091 :Toffee Apple STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt STR_2093 :Doughnut STR_2094 :Coffee @@ -2342,7 +2342,7 @@ STR_2337 :Deutschmark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseta (Pts) STR_2340 :Lira (L) -STR_2341 :Guilders (Dfl.) +STR_2341 :Guilders (fl.) STR_2342 :Krona (kr) STR_2343 :Euros ({EURO}) STR_2344 :Imperial @@ -2682,37 +2682,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Never +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. STR_2711 :; STR_2712 := STR_2713 :, @@ -2720,46 +2720,46 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(up) +STR_2719 :(new file) +STR_2720 :{UINT16}sec +STR_2721 :{UINT16}secs +STR_2722 :{UINT16}min:{UINT16}sec +STR_2723 :{UINT16}min:{UINT16}secs +STR_2724 :{UINT16}mins:{UINT16}sec +STR_2725 :{UINT16}mins:{UINT16}secs +STR_2726 :{UINT16}min +STR_2727 :{UINT16}mins +STR_2728 :{UINT16}hour:{UINT16}min +STR_2729 :{UINT16}hour:{UINT16}mins +STR_2730 :{UINT16}hours:{UINT16}min +STR_2731 :{UINT16}hours:{UINT16}mins +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Year {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Year {COMMA16} +STR_2738 :Title screen music: +STR_2739 :None +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat not found +STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat in your RCT2 installation. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? +STR_2749 :My new scenario # New strings used in the cheats window previously these were ??? +STR_2750 :Move all items to top +STR_2751 :Move all items to bottom +STR_2752 :Clear grass +STR_2753 :Mowed grass +STR_2754 :Water plants +STR_2755 :Fix vandalism +STR_2756 :Remove litter STR_2757 :Force Sun STR_2758 :Force Thunder STR_2759 :Zero Clearance @@ -2769,7 +2769,7 @@ STR_2762 :Pay For Rides STR_2763 :??? STR_2764 :Happy Guests STR_2765 :Large Tram -STR_2766 :??? +STR_2766 :Win scenario STR_2767 :Freeze Climate STR_2768 :Unfreeze Climate STR_2769 :Open Park @@ -2779,7 +2779,7 @@ STR_2772 :Faster Gamespeed STR_2773 :Windowed STR_2774 :Fullscreen STR_2775 :Fullscreen (desktop) -STR_2776 :Language +STR_2776 :Language: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} STR_2779 :Viewport #{COMMA16} @@ -2815,7 +2815,7 @@ STR_2807 :{RED}Guests are complaining about the amount of litter in your park STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organizing them better STR_2809 :{RED}Guests are hungry and can't find anywhere to buy food STR_2810 :{RED}Guests are thirsty and can't find anywhere to buy drinks -STR_2811 :{RED}Guests are complaining because they can't find the restrooms in your park +STR_2811 :{RED}Guests are complaining because they can't find the toilets in your park STR_2812 :{RED}Guests are getting lost or stuck{NEWLINE}Check whether the layout of your footpaths needs improving to help the guests find their way around STR_2813 :{RED}Your park entrance fee is too high!{NEWLINE}Reduce your entrance fee or improve the value of the park to attract more guests STR_2814 :{WINDOW_COLOUR_2}Most untidy park award @@ -2828,7 +2828,7 @@ STR_2820 :{WINDOW_COLOUR_2}Safest park award STR_2821 :{WINDOW_COLOUR_2}Best staff award STR_2822 :{WINDOW_COLOUR_2}Best park food award STR_2823 :{WINDOW_COLOUR_2}Worst park food award -STR_2824 :{WINDOW_COLOUR_2}Best park restrooms award +STR_2824 :{WINDOW_COLOUR_2}Best park toilets award STR_2825 :{WINDOW_COLOUR_2}Most disappointing park award STR_2826 :{WINDOW_COLOUR_2}Best water rides award STR_2827 :{WINDOW_COLOUR_2}Best custom-designed rides award @@ -2845,7 +2845,7 @@ STR_2837 :{TOPAZ}Your park has received an award for being 'The safest park i STR_2838 :{TOPAZ}Your park has received an award for being 'The park with the best staff'! STR_2839 :{TOPAZ}Your park has received an award for being 'The park with the best food in the country'! STR_2840 :{TOPAZ}Your park has received an award for being 'The park with the worst food in the country'! -STR_2841 :{TOPAZ}Your park has received an award for being 'The park with the best restroom facilities in the country'! +STR_2841 :{TOPAZ}Your park has received an award for being 'The park with the best toilet facilities in the country'! STR_2842 :{TOPAZ}Your park has received an award for being 'The most disappointing park in the country'! STR_2843 :{TOPAZ}Your park has received an award for being 'The park with the best water rides in the country'! STR_2844 :{TOPAZ}Your park has received an award for being 'The park with the best custom-designed rides'! @@ -3376,8 +3376,8 @@ STR_3368 :{BLACK}= Drink Stall STR_3369 :{BLACK}= Souvenir Stall STR_3370 :{BLACK}= Info. Kiosk STR_3371 :{BLACK}= First Aid -STR_3372 :{BLACK}= A.T.M. -STR_3373 :{BLACK}= Restroom +STR_3372 :{BLACK}= Cash Machine +STR_3373 :{BLACK}= Toilet STR_3374 :Warning: Too many objects selected! STR_3375 :Not all objects in this scenery group could be selected STR_3376 :Install new track design... @@ -3451,3 +3451,235 @@ STR_3443 :Page 4 STR_3444 :Page 5 STR_3445 :Set Patrol Area STR_3446 :Cancel Patrol Area + +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renew rides +STR_5124 :No Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +STR_5151 :, +STR_5152 :. +STR_5153 :Edit Themes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpath +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear +STR_5278 :Sandbox mode +STR_5279 :Sandbox mode off +STR_5280 :{SMALLFONT}{BLACK}Allow editing land ownership settings through the Map window and other options that are normally restricted to the Scenario Editor +STR_5281 :{SMALLFONT}{BLACK}Features +STR_5282 :RCT1 Ride Open/Close Lights +STR_5283 :RCT1 Park Open/Close Lights +STR_5284 :RCT1 Scenario Selection Font +STR_5285 :EXPLODE!!! +STR_5286 :{MEDIUMFONT}{BLACK}Makes guests explode +STR_5287 :Ride is already broken down +STR_5288 :Ride is closed +STR_5289 :No breakdowns available for this ride +STR_5290 :Fix ride +STR_5291 :Can't force breakdown +STR_5292 :{SMALLFONT}{BLACK}Force a breakdown +STR_5293 :{SMALLFONT}{BLACK}Close ride/attraction +STR_5294 :{SMALLFONT}{BLACK}Test ride/attraction +STR_5295 :{SMALLFONT}{BLACK}Open ride/attraction +STR_5296 :{SMALLFONT}{BLACK}Close park +STR_5297 :{SMALLFONT}{BLACK}Open park +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}Quick fire staff +STR_5301 :{MEDIUMFONT}{BLACK}Clear your loan +STR_5302 :Clear loan +STR_5303 :Allow building in pause mode +STR_5304 :Title Sequence: +STR_5305 :RollerCoaster Tycoon 1 +STR_5306 :RollerCoaster Tycoon 1 (AA) +STR_5307 :RollerCoaster Tycoon 1 (AA + LL) +STR_5308 :RollerCoaster Tycoon 2 +STR_5309 :OpenRCT2 +STR_5310 :Random +STR_5311 :{SMALLFONT}{BLACK}Debug tools +STR_5312 :Show console +STR_5313 :Show tile inspector +STR_5314 :Tile inspector +STR_5315 :Grass +STR_5316 :Sand +STR_5317 :Dirt +STR_5318 :Rock +STR_5319 :Martian +STR_5320 :Checkerboard +STR_5321 :Grass clumps +STR_5322 :Ice +STR_5323 :Grid (red) +STR_5324 :Grid (yellow) +STR_5325 :Grid (blue) +STR_5326 :Grid (green) +STR_5327 :Sand (dark) +STR_5328 :Sand (light) +STR_5329 :Checkerboard (inverted) +STR_5330 :Underground view +STR_5331 :Rock +STR_5332 :Wood (red) +STR_5333 :Wood (black) +STR_5334 :Ice +STR_5335 :Ride entrance +STR_5336 :Ride exit +STR_5337 :Park entrance +STR_5338 :Element type +STR_5339 :Base height +STR_5340 :Clearance height +STR_5341 :Flags +STR_5342 :Choose a map tile +STR_5343 :Automatically place staff +STR_5344 :Changelog +STR_5345 :Financial cheats +STR_5346 :Guest cheats +STR_5347 :Ride cheats +STR_5348 :Park cheats +STR_5349 :{SMALLFONT}{BLACK}All Rides \ No newline at end of file diff --git a/data/language/english_us.txt b/data/language/english_us.txt index b3e187b88b..f5ecc67ee3 100644 --- a/data/language/english_us.txt +++ b/data/language/english_us.txt @@ -3,97 +3,97 @@ # Use # at the beginning of a line to leave a comment. STR_0000 : STR_0001 :{STRINGID} {COMMA16} -STR_0002 :Ride -STR_0003 :Ride +STR_0002 :Spiral Roller Coaster +STR_0003 :Stand-up Roller Coaster STR_0004 :Suspended Swinging Coaster -STR_0005 :Ride +STR_0005 :Inverted Roller Coaster STR_0006 :Junior Roller Coaster -STR_0007 :Miniature Railway +STR_0007 :Miniature Railroad STR_0008 :Monorail STR_0009 :Mini Suspended Coaster -STR_0010 :Ride -STR_0011 :Ride -STR_0012 :Ride +STR_0010 :Boat Hire +STR_0011 :Wooden Wild Mouse +STR_0012 :Steeplechase STR_0013 :Car Ride -STR_0014 :Ride -STR_0015 :Ride -STR_0016 :Ride +STR_0014 :Launched Freefall +STR_0015 :Bobsled Coaster +STR_0016 :Observation Tower STR_0017 :Looping Roller Coaster -STR_0018 :Ride -STR_0019 :Ride +STR_0018 :Dinghy Slide +STR_0019 :Mine Train Coaster STR_0020 :Chairlift -STR_0021 :Ride -STR_0022 :Ride -STR_0023 :Ride -STR_0024 :Ride -STR_0025 :Ride -STR_0026 :Ride -STR_0027 :Ride -STR_0028 :Ride -STR_0029 :Ride -STR_0030 :Stall -STR_0031 :Stall -STR_0032 :Stall -STR_0033 :Stall -STR_0034 :Stall -STR_0035 :Ride -STR_0036 :Stall -STR_0037 :Kiosk +STR_0021 :Corkscrew Roller Coaster +STR_0022 :Maze +STR_0023 :Spiral Slide +STR_0024 :Go Karts +STR_0025 :Log Flume +STR_0026 :River Rapids +STR_0027 :Bumper Cars +STR_0028 :Pirate Ship +STR_0029 :Swinging Inverter Ship +STR_0030 :Food Stall +STR_0031 :Unknown Stall (1D) +STR_0032 :Drink Stall +STR_0033 :Unknown Stall (1F) +STR_0034 :Shop +STR_0035 :Carousel +STR_0036 :Unknown Stall (22) +STR_0037 :Information Kiosk STR_0038 :Restroom -STR_0039 :Ride -STR_0040 :Ride -STR_0041 :Ride -STR_0042 :Ride -STR_0043 :Ride +STR_0039 :Ferris Wheel +STR_0040 :Motion Simulator +STR_0041 :3D Theater +STR_0042 :Top Spin +STR_0043 :Space Rings STR_0044 :Reverse Freefall Coaster -STR_0045 :Lift -STR_0046 :Ride -STR_0047 :Ride -STR_0048 :Ride -STR_0049 :Ride -STR_0050 :Ride -STR_0051 :Ride -STR_0052 :Ride -STR_0053 :Hyper-Twister Roller Coaster +STR_0045 :Elevator +STR_0046 :Vertical Drop Roller Coaster +STR_0047 :ATM +STR_0048 :Twist +STR_0049 :Haunted House +STR_0050 :First Aid Room +STR_0051 :Circus Show +STR_0052 :Tunnel Of Horror +STR_0053 :Twister Roller Coaster STR_0054 :Wooden Roller Coaster STR_0055 :Side-Friction Roller Coaster STR_0056 :Wild Mouse STR_0057 :Multi-Dimension Roller Coaster -STR_0058 :Ride -STR_0059 :Aerial Inverted Roller Coaster -STR_0060 :Ride -STR_0061 :Ride -STR_0062 :Ride -STR_0063 :Ride -STR_0064 :Ride +STR_0058 :Unknown Ride (38) +STR_0059 :Flying Roller Coaster +STR_0060 :Unknown Ride (3A) +STR_0061 :Virginia Reel +STR_0062 :Splash Boats +STR_0063 :Mini Helicopters +STR_0064 :Lay-down Roller Coaster STR_0065 :Suspended Monorail -STR_0066 :Ride -STR_0067 :Ride +STR_0066 :Unknown Ride (40) +STR_0067 :Reverser Roller Coaster STR_0068 :Heartline Twister Coaster -STR_0069 :Ride -STR_0070 :Ride -STR_0071 :Ride -STR_0072 :Ride -STR_0073 :Ride -STR_0074 :Ride -STR_0075 :Ride +STR_0069 :Mini Golf +STR_0070 :Giga Coaster +STR_0071 :Roto-Drop +STR_0072 :Flying Saucers +STR_0073 :Crooked House +STR_0074 :Monorail Cycles +STR_0075 :Compact Inverted Coaster STR_0076 :Water Coaster -STR_0077 :Ride -STR_0078 :Ride -STR_0079 :Ride -STR_0080 :Ride -STR_0081 :Ride -STR_0082 :Ride -STR_0083 :Ride -STR_0084 :Ride -STR_0085 :Ride -STR_0086 :Ride -STR_0087 :Ride -STR_0088 :Ride +STR_0077 :Air Powered Vertical Coaster +STR_0078 :Inverted Hairpin Coaster +STR_0079 :Magic Carpet +STR_0080 :Submarine Ride +STR_0081 :River Rafts +STR_0082 :Unknown Ride (50) +STR_0083 :Enterprise +STR_0084 :Unknown Ride (52) +STR_0085 :Unknown Ride (53) +STR_0086 :Unknown Ride (54) +STR_0087 :Unknown Ride (55) +STR_0088 :Inverted Impulse Coaster STR_0089 :Mini Roller Coaster -STR_0090 :Ride -STR_0091 :Ride -STR_0092 :Ride +STR_0090 :Mine Ride +STR_0091 :Unknown Ride (59) +STR_0092 :LIM Launched Roller Coaster STR_0093 : STR_0094 : STR_0095 : @@ -1065,7 +1065,7 @@ STR_1060 :Invalid ride/attraction name STR_1061 :Normal mode STR_1062 :Continuous circuit mode STR_1063 :Reverse-Incline launched shuttle mode -STR_1064 :Powered launch +STR_1064 :Powered launch (passing station) STR_1065 :Shuttle mode STR_1066 :Boat hire mode STR_1067 :Upward launch @@ -1097,7 +1097,7 @@ STR_1092 :Downward launch STR_1093 :Crooked house mode STR_1094 :Freefall drop mode STR_1095 :Continuous circuit block sectioned mode -STR_1096 :Powered launch +STR_1096 :Powered launch (without passing station) STR_1097 :Powered launch block sectioned mode STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} @@ -1778,7 +1778,7 @@ STR_1773 :Only one on-ride photo section allowed per ride STR_1774 :Only one cable lift hill allowed per ride STR_1775 :Off STR_1776 :On -STR_1777 :{WINDOW_COLOUR_2}Music: +STR_1777 :{WINDOW_COLOUR_2}Music STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigre costume @@ -1842,7 +1842,7 @@ STR_1837 :Satisfaction: Unknown STR_1838 :Satisfaction: {COMMA16}% STR_1839 :Reliability: {COMMA16}% STR_1840 :Down-time: {COMMA16}% -STR_1841 :Profit: {CURRENCY} per hour +STR_1841 :Profit: {CURRENCY2DP} per hour STR_1842 :Favorite of: {COMMA16} guest STR_1843 :Favorite of: {COMMA16} guests STR_1844 :{SMALLFONT}{BLACK}Select information type to show in ride/attraction list @@ -1859,7 +1859,7 @@ STR_1854 :{WINDOW_COLOUR_2}Built: {BLACK}Last Year STR_1855 :{WINDOW_COLOUR_2}Built: {BLACK}{COMMA16} Years Ago STR_1856 :{WINDOW_COLOUR_2}Profit per item sold: {BLACK}{CURRENCY2DP} STR_1857 :{WINDOW_COLOUR_2}Loss per item sold: {BLACK}{CURRENCY2DP} -STR_1858 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} per month +STR_1858 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY2DP} per month STR_1859 :Handymen STR_1860 :Mechanics STR_1861 :Security Guards @@ -1874,8 +1874,8 @@ STR_1869 :{WINDOW_COLOUR_2}Number of rotations: STR_1870 :{SMALLFONT}{BLACK}Number of complete rotations STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1872 :{COMMA16} -STR_1873 :{WINDOW_COLOUR_2}Income: {BLACK}{CURRENCY} per hour -STR_1874 :{WINDOW_COLOUR_2}Profit: {BLACK}{CURRENCY} per hour +STR_1873 :{WINDOW_COLOUR_2}Income: {BLACK}{CURRENCY2DP} per hour +STR_1874 :{WINDOW_COLOUR_2}Profit: {BLACK}{CURRENCY2DP} per hour STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Inspect Rides STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Fix Rides @@ -2342,7 +2342,7 @@ STR_2337 :Deutschmark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseta (Pts) STR_2340 :Lira (L) -STR_2341 :Guilders (Dfl.) +STR_2341 :Guilders (fl.) STR_2342 :Krona (kr) STR_2343 :Euros ({EURO}) STR_2344 :Imperial @@ -2526,6 +2526,7 @@ STR_2521 :Show staff list STR_2522 :Show recent messages STR_2523 :Show map STR_2524 :Screenshot + STR_2525 :??? STR_2526 :??? STR_2527 :??? @@ -2681,37 +2682,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Never +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. STR_2711 :; STR_2712 := STR_2713 :, @@ -2719,56 +2720,57 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(up) +STR_2719 :(new file) +STR_2720 :{UINT16}sec +STR_2721 :{UINT16}secs +STR_2722 :{UINT16}min:{UINT16}sec +STR_2723 :{UINT16}min:{UINT16}secs +STR_2724 :{UINT16}mins:{UINT16}sec +STR_2725 :{UINT16}mins:{UINT16}secs +STR_2726 :{UINT16}min +STR_2727 :{UINT16}mins +STR_2728 :{UINT16}hour:{UINT16}min +STR_2729 :{UINT16}hour:{UINT16}mins +STR_2730 :{UINT16}hours:{UINT16}min +STR_2731 :{UINT16}hours:{UINT16}mins +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Year {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Year {COMMA16} +STR_2738 :Title screen music: +STR_2739 :None +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat not found +STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat in your RCT2 installation. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? -STR_2757 :??? -STR_2758 :??? -STR_2759 :??? +STR_2749 :My new scenario + # New strings used in the cheats window previously these were ??? +STR_2750 :Move all items to top +STR_2751 :Move all items to bottom +STR_2752 :Clear grass +STR_2753 :Mowed grass +STR_2754 :Water plants +STR_2755 :Fix vandalism +STR_2756 :Remove litter +STR_2757 :Force Sun +STR_2758 :Force Thunder +STR_2759 :Zero Clearance STR_2760 :+5K Money STR_2761 :Pay For Entrance STR_2762 :Pay For Rides STR_2763 :??? STR_2764 :Happy Guests STR_2765 :Large Tram -STR_2766 :??? +STR_2766 :Win scenario STR_2767 :Freeze Climate STR_2768 :Unfreeze Climate STR_2769 :Open Park @@ -2778,12 +2780,14 @@ STR_2772 :Faster Gamespeed STR_2773 :Windowed STR_2774 :Fullscreen STR_2775 :Fullscreen (desktop) -STR_2776 :Language +STR_2776 :Language: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +STR_2779 :Viewport #{COMMA16} +STR_2780 :Extra viewport # End of new strings -STR_2779 :??? -STR_2780 :??? + + STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + @@ -3450,3 +3454,232 @@ STR_3443 :Page 4 STR_3444 :Page 5 STR_3445 :Set Patrol Area STR_3446 :Cancel Patrol Area + +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renew rides +STR_5124 :No Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +#Thousands separator +STR_5151 :, +#Decimals separator +STR_5152 :. +STR_5153 :Color schemes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpaths +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear +STR_5278 :Sandbox mode +STR_5279 :Sandbox mode off +STR_5280 :{SMALLFONT}{BLACK}Allow editing land ownership settings through the Map window and other options that are normally restricted to the Scenario Editor +STR_5281 :{SMALLFONT}{BLACK}Features +STR_5282 :RCT1 Ride Open/Close Lights +STR_5283 :RCT1 Park Open/Close Lights +STR_5284 :RCT1 Scenario Selection Font +STR_5285 :EXPLODE!!! +STR_5286 :{MEDIUMFONT}{BLACK}Makes guests explode +STR_5287 :Ride is already broken down +STR_5288 :Ride is closed +STR_5289 :No breakdowns available for this ride +STR_5290 :Fix ride +STR_5291 :Can't force breakdown +STR_5292 :{SMALLFONT}{BLACK}Force a breakdown +STR_5293 :{SMALLFONT}{BLACK}Close ride/attraction +STR_5294 :{SMALLFONT}{BLACK}Test ride/attraction +STR_5295 :{SMALLFONT}{BLACK}Open ride/attraction +STR_5296 :{SMALLFONT}{BLACK}Close park +STR_5297 :{SMALLFONT}{BLACK}Open park +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}Quick fire staff +STR_5301 :{MEDIUMFONT}{BLACK}Clear your loan +STR_5302 :Clear loan +STR_5303 :Allow building in pause mode +STR_5304 :Title Sequence: +STR_5305 :RollerCoaster Tycoon 1 +STR_5306 :RollerCoaster Tycoon 1 (AA) +STR_5307 :RollerCoaster Tycoon 1 (AA + LL) +STR_5308 :RollerCoaster Tycoon 2 +STR_5309 :OpenRCT2 +STR_5310 :Random +STR_5311 :{SMALLFONT}{BLACK}Debug tools +STR_5312 :Show console +STR_5313 :Show tile inspector +STR_5314 :Tile inspector +STR_5315 :Grass +STR_5316 :Sand +STR_5317 :Dirt +STR_5318 :Rock +STR_5319 :Martian +STR_5320 :Checkerboard +STR_5321 :Grass clumps +STR_5322 :Ice +STR_5323 :Grid (red) +STR_5324 :Grid (yellow) +STR_5325 :Grid (blue) +STR_5326 :Grid (green) +STR_5327 :Sand (dark) +STR_5328 :Sand (light) +STR_5329 :Checkerboard (inverted) +STR_5330 :Underground view +STR_5331 :Rock +STR_5332 :Wood (red) +STR_5333 :Wood (black) +STR_5334 :Ice +STR_5335 :Ride entrance +STR_5336 :Ride exit +STR_5337 :Park entrance +STR_5338 :Element type +STR_5339 :Base height +STR_5340 :Clearance height +STR_5341 :Flags +STR_5342 :Choose a map tile +STR_5343 :Automatically place staff +STR_5344 :Changelog diff --git a/data/language/french.txt b/data/language/french.txt index d689041161..3322f1656a 100644 --- a/data/language/french.txt +++ b/data/language/french.txt @@ -3,97 +3,97 @@ # Use # at the beginning of a line to leave a comment. STR_0000 : STR_0001 :{STRINGID} {COMMA16} -STR_0002 :Ride -STR_0003 :Ride +STR_0002 :Attraction +STR_0003 :Attraction STR_0004 :Suspended Swinging Coaster -STR_0005 :Ride +STR_0005 :Attraction STR_0006 :Junior Roller Coaster STR_0007 :Miniature Railway STR_0008 :Monorail STR_0009 :Mini Suspended Coaster -STR_0010 :Ride -STR_0011 :Ride -STR_0012 :Ride +STR_0010 :Attraction +STR_0011 :Attraction +STR_0012 :Attraction STR_0013 :Car Ride -STR_0014 :Ride -STR_0015 :Ride -STR_0016 :Ride +STR_0014 :Attraction +STR_0015 :Attraction +STR_0016 :Attraction STR_0017 :Looping Roller Coaster -STR_0018 :Ride -STR_0019 :Ride +STR_0018 :Attraction +STR_0019 :Attraction STR_0020 :Chairlift -STR_0021 :Ride -STR_0022 :Ride -STR_0023 :Ride -STR_0024 :Ride -STR_0025 :Ride -STR_0026 :Ride -STR_0027 :Ride -STR_0028 :Ride -STR_0029 :Ride +STR_0021 :Attraction +STR_0022 :Attraction +STR_0023 :Attraction +STR_0024 :Attraction +STR_0025 :Attraction +STR_0026 :Attraction +STR_0027 :Attraction +STR_0028 :Attraction +STR_0029 :Attraction STR_0030 :Stall STR_0031 :Stall STR_0032 :Stall STR_0033 :Stall STR_0034 :Stall -STR_0035 :Ride +STR_0035 :Attraction STR_0036 :Stall STR_0037 :Kiosk -STR_0038 :Restroom -STR_0039 :Ride -STR_0040 :Ride -STR_0041 :Ride -STR_0042 :Ride -STR_0043 :Ride +STR_0038 :Toilettes +STR_0039 :Attraction +STR_0040 :Attraction +STR_0041 :Attraction +STR_0042 :Attraction +STR_0043 :Attraction STR_0044 :Reverse Freefall Coaster STR_0045 :Lift -STR_0046 :Ride -STR_0047 :Ride -STR_0048 :Ride -STR_0049 :Ride -STR_0050 :Ride -STR_0051 :Ride -STR_0052 :Ride +STR_0046 :Attraction +STR_0047 :Attraction +STR_0048 :Attraction +STR_0049 :Attraction +STR_0050 :Attraction +STR_0051 :Attraction +STR_0052 :Attraction STR_0053 :Hyper-Twister Roller Coaster STR_0054 :Wooden Roller Coaster STR_0055 :Side-Friction Roller Coaster STR_0056 :Wild Mouse STR_0057 :Multi-Dimension Roller Coaster -STR_0058 :Ride +STR_0058 :Attraction STR_0059 :Aerial Inverted Roller Coaster -STR_0060 :Ride -STR_0061 :Ride -STR_0062 :Ride -STR_0063 :Ride -STR_0064 :Ride +STR_0060 :Attraction +STR_0061 :Attraction +STR_0062 :Attraction +STR_0063 :Attraction +STR_0064 :Attraction STR_0065 :Suspended Monorail -STR_0066 :Ride -STR_0067 :Ride +STR_0066 :Attraction +STR_0067 :Attraction STR_0068 :Heartline Twister Coaster -STR_0069 :Ride -STR_0070 :Ride -STR_0071 :Ride -STR_0072 :Ride -STR_0073 :Ride -STR_0074 :Ride -STR_0075 :Ride +STR_0069 :Attraction +STR_0070 :Attraction +STR_0071 :Attraction +STR_0072 :Attraction +STR_0073 :Attraction +STR_0074 :Attraction +STR_0075 :Attraction STR_0076 :Water Coaster -STR_0077 :Ride -STR_0078 :Ride -STR_0079 :Ride -STR_0080 :Ride -STR_0081 :Ride -STR_0082 :Ride -STR_0083 :Ride -STR_0084 :Ride -STR_0085 :Ride -STR_0086 :Ride -STR_0087 :Ride -STR_0088 :Ride +STR_0077 :Attraction +STR_0078 :Attraction +STR_0079 :Attraction +STR_0080 :Attraction +STR_0081 :Attraction +STR_0082 :Attraction +STR_0083 :Attraction +STR_0084 :Attraction +STR_0085 :Attraction +STR_0086 :Attraction +STR_0087 :Attraction +STR_0088 :Attraction STR_0089 :Mini Roller Coaster -STR_0090 :Ride -STR_0091 :Ride -STR_0092 :Ride +STR_0090 :Attraction +STR_0091 :Attraction +STR_0092 :Attraction STR_0093 : STR_0094 : STR_0095 : @@ -842,7 +842,7 @@ STR_0837 :Unable to initialize graphics system STR_0838 :CD key code {INT32} is not valid for your RollerCoaster Tycoon 2 CD !{WINDOW_COLOUR_1}{WINDOW_COLOUR_1}Please un-install RollerCoaster Tycoon 2% and re-install with the correct CD Key Code STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Desktop window +STR_0841 :En une fenêtre STR_0842 :640x480 plein écran STR_0843 :800x600 plein écran STR_0844 :1024x768 plein écran @@ -973,7 +973,7 @@ STR_0968 :+360{DEGREE} STR_0969 :+405{DEGREE} STR_0970 :+450{DEGREE} STR_0971 :+495{DEGREE} -STR_0972 :Cancel +STR_0972 :Annuler STR_0973 :OK STR_0974 :Rides STR_0975 :Shops and Stalls @@ -1065,7 +1065,7 @@ STR_1060 :Invalid ride/attraction name STR_1061 :Normal mode STR_1062 :Continuous circuit mode STR_1063 :Reverse-Incline launched shuttle mode -STR_1064 :Powered launch +STR_1064 :Lancement (avec passage de la station) STR_1065 :Shuttle mode STR_1066 :Boat hire mode STR_1067 :Upward launch @@ -1097,7 +1097,7 @@ STR_1092 :Downward launch STR_1093 :Crooked house mode STR_1094 :Freefall drop mode STR_1095 :Continuous circuit block sectioned mode -STR_1096 :Powered launch +STR_1096 :Lancement (sans passage de la station) STR_1097 :Powered launch block sectioned mode STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} @@ -1272,13 +1272,13 @@ STR_1267 :Cars STR_1268 :{COMMA16} car STR_1269 :{COMMA16} cars STR_1270 :Car {COMMA16} -STR_1271 :building -STR_1272 :buildings -STR_1273 :Building -STR_1274 :Buildings -STR_1275 :{COMMA16} building -STR_1276 :{COMMA16} buildings -STR_1277 :Building {COMMA16} +STR_1271 :bâtiment +STR_1272 :bâtiments +STR_1273 :Bâtiment +STR_1274 :Bâtiment +STR_1275 :{COMMA16} bâtiment +STR_1276 :{COMMA16} bâtiments +STR_1277 :Bâtiment {COMMA16} STR_1278 :structure STR_1279 :structures STR_1280 :Structure @@ -1336,10 +1336,10 @@ STR_1331 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VEL STR_1332 :{VELOCITY} STR_1333 :{STRINGID} - {STRINGID}{POP16} STR_1334 :{STRINGID} - {STRINGID} {COMMA16} -STR_1335 :{STRINGID} - Entrance{POP16}{POP16} -STR_1336 :{STRINGID} - Station {POP16}{COMMA16} Entrance -STR_1337 :{STRINGID} - Exit{POP16}{POP16} -STR_1338 :{STRINGID} - Station {POP16}{COMMA16} Exit +STR_1335 :{STRINGID} - Entrée{POP16}{POP16} +STR_1336 :{STRINGID} - Entrée de station {POP16}{COMMA16} +STR_1337 :{STRINGID} - Sortie{POP16}{POP16} +STR_1338 :{STRINGID} - Sortie de station {POP16}{COMMA16} STR_1339 :{BLACK}No test results yet... STR_1340 :{WINDOW_COLOUR_2}Max. speed: {BLACK}{VELOCITY} STR_1341 :{WINDOW_COLOUR_2}Ride time: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} @@ -1416,7 +1416,7 @@ STR_1411 :{STRINGID} in the way STR_1412 :{WINDOW_COLOUR_3}Data logging not available for this type of ride STR_1413 :{WINDOW_COLOUR_3}Data logging will start when next {STRINGID} leaves {STRINGID} STR_1414 :{SMALLFONT}{BLACK}{DURATION} -STR_1415 :{WINDOW_COLOUR_2}Velocity +STR_1415 :{WINDOW_COLOUR_2}Vitesse STR_1416 :{WINDOW_COLOUR_2}Altitude STR_1417 :{WINDOW_COLOUR_2}Vert.G's STR_1418 :{WINDOW_COLOUR_2}Lat.G's @@ -1431,14 +1431,14 @@ STR_1426 :Queue Line STR_1427 :{WINDOW_COLOUR_2}Clients: {BLACK}{COMMA32} par heure STR_1428 :{WINDOW_COLOUR_2}Admission price: STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} -STR_1430 :Free +STR_1430 :Gratuit STR_1431 :Marche STR_1432 :Heading for {STRINGID} STR_1433 :Queuing for {STRINGID} STR_1434 :Drowning -STR_1435 :On {STRINGID} -STR_1436 :In {STRINGID} -STR_1437 :At {STRINGID} +STR_1435 :En {STRINGID} +STR_1436 :Dans {STRINGID} +STR_1437 :A {STRINGID} STR_1438 :Sitting STR_1439 :(select location) STR_1440 :Mowing grass @@ -1453,7 +1453,7 @@ STR_1448 :Watching new ride being constructed STR_1449 :{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) STR_1450 :{INLINE_SPRITE}{09}{20}{00}{00}{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) STR_1451 :{STRINGID}{NEWLINE}({STRINGID}) -STR_1452 :Guest's name +STR_1452 :Nom du visiteur STR_1453 :Enter name for this guest: STR_1454 :Can't name guest... STR_1455 :Invalid name for guest @@ -1464,15 +1464,15 @@ STR_1459 :Track style STR_1460 :{SMALLFONT}{BLACK}'U' shaped open track STR_1461 :{SMALLFONT}{BLACK}'O' shaped enclosed track STR_1462 :Too steep for lift hill -STR_1463 :Guests +STR_1463 :Visiteurs STR_1464 :Helix up (small) STR_1465 :Helix up (large) STR_1466 :Helix down (small) STR_1467 :Helix down (large) -STR_1468 :Staff +STR_1468 :Personnel STR_1469 :Ride must start and end with stations STR_1470 :Station not long enough -STR_1471 :{WINDOW_COLOUR_2}Speed: +STR_1471 :{WINDOW_COLOUR_2}Vitesse: STR_1472 :{SMALLFONT}{BLACK}Speed of this ride STR_1473 :{WINDOW_COLOUR_2}Excitement rating: {BLACK}{COMMA2DP32} ({STRINGID}) STR_1474 :{WINDOW_COLOUR_2}Excitement rating: {BLACK}Not yet available @@ -1673,7 +1673,7 @@ STR_1668 :{WINDOW_COLOUR_2}Satisfaction: {BLACK}Unknown STR_1669 :{WINDOW_COLOUR_2}Satisfaction: {BLACK}{COMMA16}% STR_1670 :{WINDOW_COLOUR_2}Total customers: {BLACK}{COMMA32} STR_1671 :{WINDOW_COLOUR_2}Total profit: {BLACK}{CURRENCY2DP} -STR_1672 :Brakes +STR_1672 :Freins STR_1673 :Spinning Control Toggle Track STR_1674 :Brake speed STR_1675 :{POP16}{VELOCITY} @@ -1694,7 +1694,7 @@ STR_1689 :Block brakes STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} STR_1691 :{WINDOW_COLOUR_2} Cost: {BLACK}{CURRENCY} STR_1692 :{WINDOW_COLOUR_2} Cost: {BLACK}from {CURRENCY} -STR_1693 :{SMALLFONT}{BLACK}Guests +STR_1693 :{SMALLFONT}{BLACK}Visiteurs STR_1694 :{SMALLFONT}{BLACK}Staff STR_1695 :{SMALLFONT}{BLACK}Income and costs STR_1696 :{SMALLFONT}{BLACK}Customer information @@ -1711,7 +1711,7 @@ STR_1706 :{SMALLFONT}{BLACK}Move this person to a new location STR_1707 :Too many staff in game STR_1708 :{SMALLFONT}{BLACK}Set patrol area for this staff member STR_1709 :Sack staff -STR_1710 :Yes +STR_1710 :Oui STR_1711 :{WINDOW_COLOUR_1}Are you sure you want to sack {STRINGID}? STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2}Sweep footpaths STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2}Water gardens @@ -1778,7 +1778,7 @@ STR_1773 :Only one on-ride photo section allowed per ride STR_1774 :Only one cable lift hill allowed per ride STR_1775 :Off STR_1776 :On -STR_1777 :{WINDOW_COLOUR_2}Music: +STR_1777 :{WINDOW_COLOUR_2}Music STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigre costume @@ -2334,7 +2334,7 @@ STR_2329 :{WINDOW_COLOUR_2}Distance and Speed: STR_2330 :{WINDOW_COLOUR_2}Temperature: STR_2331 :{WINDOW_COLOUR_2}Height Labels: STR_2332 :Units -STR_2333 :Sound +STR_2333 :Son STR_2334 :Pounds ({POUND}) STR_2335 :Dollars ($) STR_2336 :Franc (F) @@ -2342,7 +2342,7 @@ STR_2337 :Deutschmark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseta (Pts) STR_2340 :Lira (L) -STR_2341 :Guilders (Dfl.) +STR_2341 :Florins (fl.) STR_2342 :Krona (kr) STR_2343 :Euros ({EURO}) STR_2344 :Imperial @@ -2386,7 +2386,7 @@ STR_2381 :{SMALLFONT}{BLACK}Adjust larger area of water STR_2382 :Land STR_2383 :Water STR_2384 :{WINDOW_COLOUR_2}Votre objectif: -STR_2385 :{BLACK}None +STR_2385 :{BLACK}Aucun STR_2386 :{BLACK}To have at least {COMMA16} guests in your park at the end of {MONTHYEAR}, with a park rating of at least 600 STR_2387 :{BLACK}To achieve a park value of at least {POP16}{POP16}{CURRENCY} at the end of {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR} STR_2388 :{BLACK}Have Fun! @@ -2398,7 +2398,7 @@ STR_2393 :{BLACK}To have 10 different types of roller coasters operating in y STR_2394 :{BLACK}To finish building all 5 of the partially built roller coasters in this park, designing them to achieve excitement ratings of at least {POP16}{POP16}{COMMA2DP32} each STR_2395 :{BLACK}To repay your loan and achieve a park value of at least {POP16}{POP16}{CURRENCY} STR_2396 :{BLACK}To achieve a monthly profit from food, drink and merchandise sales of at least {POP16}{POP16}{CURRENCY} -STR_2397 :None +STR_2397 :Aucun STR_2398 :Number of guests at a given date STR_2399 :Park value at a given date STR_2400 :Have fun @@ -2412,7 +2412,7 @@ STR_2407 :Repay loan and achieve a given park value STR_2408 :Monthly profit from food/merchandise STR_2409 :{WINDOW_COLOUR_2}Campagnes marketing en cours STR_2410 :{BLACK}Aucune -STR_2411 :{WINDOW_COLOUR_2}Campagnes marrketing disponibles +STR_2411 :{WINDOW_COLOUR_2}Campagnes marketing disponibles STR_2412 :{SMALLFONT}{BLACK}Commencer campagne marketing STR_2413 :{BLACK}({CURRENCY2DP} per week) STR_2414 :(Not Selected) @@ -2681,37 +2681,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Jamais +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. STR_2711 :; STR_2712 := STR_2713 :, @@ -2719,71 +2719,71 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(up) +STR_2719 :(nouveau fichier) +STR_2720 :{UINT16}s +STR_2721 :{UINT16}s +STR_2722 :{UINT16}m {UINT16}s +STR_2723 :{UINT16}m {UINT16}s +STR_2724 :{UINT16}mins:{UINT16}s +STR_2725 :{UINT16}m {UINT16}s +STR_2726 :{UINT16}m +STR_2727 :{UINT16}m +STR_2728 :{UINT16}h {UINT16}m +STR_2729 :{UINT16}h {UINT16}m +STR_2730 :{UINT16}h {UINT16}m +STR_2731 :{UINT16}h {UINT16}m +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, an {COMMA16} +STR_2737 :{STRINGID} {MONTH}, an {COMMA16} +STR_2738 :Title screen music: +STR_2739 :Aucun +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat n'est pas trouvé +STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat in your RCT2 installation. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? -STR_2757 :??? -STR_2758 :??? -STR_2759 :??? +STR_2749 :Mon nouveau scénario +STR_2750 :Move all items to top +STR_2751 :Move all items to bottom +STR_2752 :Clear grass +STR_2753 :Mowed grass +STR_2754 :Water plants +STR_2755 :Fix vandalism +STR_2756 :Remove litter +STR_2757 :Force Sun +STR_2758 :Force Thunder +STR_2759 :Zero Clearance # New strings used in the cheats window previously these were ??? -STR_2760 :+5K Money +STR_2760 :+5000 d'argent STR_2761 :Pay For Entrance STR_2762 :Pay For Rides STR_2763 :??? STR_2764 :Happy Guests STR_2765 :Large Tram -STR_2766 :??? +STR_2766 :Win scenario STR_2767 :Freeze Climate STR_2768 :Unfreeze Climate -STR_2769 :Open Park -STR_2770 :Close Park +STR_2769 :Ouvrir le parc +STR_2770 :Fermer le parc STR_2771 :Slower Gamespeed STR_2772 :Faster Gamespeed -STR_2773 :Windowed -STR_2774 :Fullscreen -STR_2775 :Fullscreen (desktop) -STR_2776 :Language +STR_2773 :En une fenêtre +STR_2774 :Plein écran +STR_2775 :Plein écran (desktop) +STR_2776 :Langue: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings -STR_2779 :??? -STR_2780 :??? +STR_2779 :Viewport #{COMMA16} +STR_2780 :Extra viewport STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + @@ -2798,14 +2798,14 @@ STR_2791 :Enter name STR_2792 :Please enter your name for the scenario chart: STR_2793 :{SMALLFONT}(Completed by {STRINGID}) STR_2794 :{WINDOW_COLOUR_2}Completed by: {BLACK}{STRINGID}{NEWLINE}{WINDOW_COLOUR_2} with a company value of: {BLACK}{CURRENCY} -STR_2795 :Sort +STR_2795 :Trier STR_2796 :{SMALLFONT}{BLACK}Sort the ride list into order using the information type displayed STR_2797 :Scroll view when pointer at screen edge STR_2798 :{SMALLFONT}{BLACK}Select whether to scroll the view when the mouse pointer is at the screen edge STR_2799 :{SMALLFONT}{BLACK}View or change control key assignments STR_2800 :{WINDOW_COLOUR_2}Total admissions: {BLACK}{COMMA32} STR_2801 :{WINDOW_COLOUR_2}Income from admissions: {BLACK}{CURRENCY2DP} -STR_2802 :Map +STR_2802 :Plan STR_2803 :{SMALLFONT}{BLACK}Show these guests highlighted on map STR_2804 :{SMALLFONT}{BLACK}Show these staff members highlighted on map STR_2805 :{SMALLFONT}{BLACK}Show map of park @@ -2984,7 +2984,7 @@ STR_2977 :Staff member name STR_2978 :Enter new name for this member of staff: STR_2979 :Can't name staff member... STR_2980 :Too many banners in game -STR_2981 :{RED}No entry - - +STR_2981 :{RED}Accès interdit - - STR_2982 :Banner text STR_2983 :Enter new text for this banner: STR_2984 :Can't set new text for banner... @@ -3058,8 +3058,8 @@ STR_3051 :Golf hole C STR_3052 :Golf hole D STR_3053 :Golf hole E STR_3054 :Loading... -STR_3055 :White -STR_3056 :Translucent +STR_3055 :Blanc +STR_3056 :Transparent STR_3057 :{WINDOW_COLOUR_2}Construction Marker: STR_3058 :Brick walls STR_3059 :Hedges @@ -3133,8 +3133,8 @@ STR_3126 :{WINDOW_COLOUR_2}Intensity Factor: {BLACK}+{COMMA16}% STR_3127 :{WINDOW_COLOUR_2}Nausea Factor: {BLACK}+{COMMA16}% STR_3128 :Save Track Design STR_3129 :Save Track Design with Scenery -STR_3130 :Save -STR_3131 :Cancel +STR_3130 :Sauvegarder +STR_3131 :Annuler STR_3132 :{BLACK}Click items of scenery to select them to be saved with track design... STR_3133 :Unable to build this on a slope STR_3134 :{RED}(Design includes scenery which is unavailable) @@ -3160,9 +3160,9 @@ STR_3153 :{SMALLFONT}{BLACK}Scroll {STRINGID} down fast STR_3154 :{SMALLFONT}{BLACK}Scroll {STRINGID} up/down STR_3155 : STR_3156 : -STR_3157 :map -STR_3158 :graph -STR_3159 :list +STR_3157 :plan +STR_3158 :graphique +STR_3159 :liste STR_3160 :RollerCoaster Tycoon 2: Première visite... STR_3161 :RollerCoaster Tycoon 2: Checking object files... STR_3162 :Unable to allocate enough memory @@ -3170,8 +3170,8 @@ STR_3163 :Installing new data: STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) STR_3165 : STR_3166 :{BLACK}(ID: -STR_3167 :{WINDOW_COLOUR_2}Includes: {BLACK}{COMMA16} objects -STR_3168 :{WINDOW_COLOUR_2}Text: {BLACK}{STRINGID} +STR_3167 :{WINDOW_COLOUR_2}Inclut: {BLACK}{COMMA16} objets +STR_3168 :{WINDOW_COLOUR_2}Texte: {BLACK}{STRINGID} STR_3169 :Data for the following object not found: STR_3170 :Not enough space for graphics STR_3171 :Too many objects of this type selected @@ -3208,7 +3208,7 @@ STR_3201 :Sélection des objets STR_3202 :Editeur de paysage STR_3203 :Liste d'inventions STR_3204 :Sélection des options -STR_3205 :Objective Selection +STR_3205 :Selection d'objectif STR_3206 :Sauvegarder scénario STR_3207 :Roller Coaster Designer STR_3208 :Track Designs Manager @@ -3289,9 +3289,9 @@ STR_3282 :{SMALLFONT}{BLACK}Choisir objectif et nom du parc STR_3283 :{SMALLFONT}{BLACK}Select rides to be preserved STR_3284 :Sélection des objectifs STR_3285 :Preserved Rides -STR_3286 :{SMALLFONT}{BLACK}Select objective for this scenario +STR_3286 :{SMALLFONT}{BLACK}Selecter un objectif pour ce scénario STR_3287 :{WINDOW_COLOUR_2}Objectif: -STR_3288 :{SMALLFONT}{BLACK}Select climate +STR_3288 :{SMALLFONT}{BLACK}Selecter climat STR_3289 :{WINDOW_COLOUR_2}Climat: STR_3290 :Frais et humide STR_3291 :Chaud @@ -3316,7 +3316,7 @@ STR_3309 :{WINDOW_COLOUR_2}{COMMA16} STR_3310 :{WINDOW_COLOUR_2}{LENGTH} STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} STR_3312 :{WINDOW_COLOUR_2}Rides/attractions under a preservation order: -STR_3313 :Scenario Name +STR_3313 :Nom du scénario: STR_3314 :Enter name for scenario: STR_3315 :Park/Scenario Details STR_3316 :Décrire ce scénario: @@ -3325,11 +3325,11 @@ STR_3318 :{SMALLFONT}{BLACK}Select which group this scenario appears in STR_3319 :{WINDOW_COLOUR_2}Scenario Group: STR_3320 :Unable to save scenario file... STR_3321 :New objects installed successfully -STR_3322 :{WINDOW_COLOUR_2}Objective: {BLACK}{STRINGID} +STR_3322 :{WINDOW_COLOUR_2}Objectif: {BLACK}{STRINGID} STR_3323 :Missing object data, ID: STR_3324 :Requires Add-On Pack: STR_3325 :Requires an Add-On Pack -STR_3326 :{WINDOW_COLOUR_2}(no image) +STR_3326 :{WINDOW_COLOUR_2}(aucune image) STR_3327 :Starting positions for people not set STR_3328 :Can't advance to next editor stage... STR_3329 :Park entrance not yet built @@ -3340,63 +3340,63 @@ STR_3333 :Export plug-in objects with saved games STR_3334 :{SMALLFONT}{BLACK}Select whether to save any additional plug-in object data required (add-in data not supplied with the main product) in saved game or scenario files, allowing them to be loaded by someone who doesn't have the additional object data STR_3335 :Roller Coaster Designer - Select Ride Types & Vehicles STR_3336 :Track Designs Manager - Select Ride Type -STR_3337 :Six Flags Park -STR_3338 :{BLACK}Custom-designed layout -STR_3339 :{BLACK}{COMMA16} design available, or custom-designed layout -STR_3340 :{BLACK}{COMMA16} designs available, or custom-designed layout +STR_3337 :Parc Six Flags +STR_3338 :{BLACK}Dispositions personnalisées +STR_3339 :{BLACK}{COMMA16} design disponible, ou disposition personnalisée +STR_3340 :{BLACK}{COMMA16} designs disponibles, ou dispositions personnalisées STR_3341 :{SMALLFONT}{BLACK}Outils STR_3342 :Editeur de scénario STR_3343 :Convertir partie sauvegardée en scénario STR_3344 :Concepteur de montages russes STR_3345 :Gestionnaire de voies -STR_3346 :Can't save track design... -STR_3347 :Ride is too large, contains too many elements, or scenery is too spread out -STR_3348 :Rename -STR_3349 :Delete -STR_3350 :Track design name -STR_3351 :Enter new name for this track design: -STR_3352 :Can't rename track design... -STR_3353 :New name contains invalid characters -STR_3354 :Another file exists with this name, or file is write-protected -STR_3355 :File is write-protected or locked -STR_3356 :Delete File -STR_3357 :{WINDOW_COLOUR_2}Are you sure you want to permanently delete {STRINGID} ? -STR_3358 :Can't delete track design... -STR_3359 :{BLACK}No track designs of this type -STR_3360 :Warning! -STR_3361 :Too many track designs of this type - Some will not be listed. -STR_3362 :Forced Software Buffer Mixing -STR_3363 :{SMALLFONT}{BLACK}Select this option to improve performance if the game pauses slightly when sounds start or interference is heard -STR_3364 :Advanced -STR_3365 :{SMALLFONT}{BLACK}Allow selection of individual items of scenery in addition to scenery groups -STR_3366 :{BLACK}= Ride -STR_3367 :{BLACK}= Food Stall -STR_3368 :{BLACK}= Drink Stall -STR_3369 :{BLACK}= Souvenir Stall -STR_3370 :{BLACK}= Info. Kiosk -STR_3371 :{BLACK}= First Aid -STR_3372 :{BLACK}= A.T.M. -STR_3373 :{BLACK}= Restroom -STR_3374 :Warning: Too many objects selected! -STR_3375 :Not all objects in this scenery group could be selected -STR_3376 :Install new track design... -STR_3377 :{SMALLFONT}{BLACK}Install a new track design file -STR_3378 :Install -STR_3379 :Cancel -STR_3380 :Unable to install this track design... -STR_3381 :File is not compatible or contains invalid data -STR_3382 :File copy failed -STR_3383 :Select new name for track design -STR_3384 :An existing track design already has this name - Please select a new name for this design: +STR_3346 :Impossible de sauvegarder le modèle du circuit... +STR_3347 :L'attraction est trop large, contient trop d'éléments, ou le décor est trop éloigné +STR_3348 :Renommer +STR_3349 :Supprimer +STR_3350 :Nom du modèle de circuit +STR_3351 :Entrez le nouveau nom du modèle du circuit : +STR_3352 :Impossible de renommer le modèle du circuit... +STR_3353 :Le nouveau nom contient des caractères invalides +STR_3354 :Un autre fichier existe avec ce nom, ou il est en lecture seule +STR_3355 :Le fichier est verrouillé ou est en lecture seule +STR_3356 :Supprimer fichier +STR_3357 :{WINDOW_COLOUR_2}Etes-vous sûr(e) de vouloir supprimer de manière permanente {STRINGID} ? +STR_3358 :Impossible de supprimer le modèle du circuit... +STR_3359 :{BLACK}Pas de modèle de circuit pour ce type +STR_3360 :Attention ! +STR_3361 :Trop de modèles de circuit pour ce type - Certains ne seront pas listés. +STR_3362 :Forcé mixage tampon logiciel +STR_3363 :{SMALLFONT}{BLACK}Selectionnez cette option pour améliorer les performances si le jeu se met légèrement en pause slightly quand les sons démarrent ou de l'interférence est entendue +STR_3364 :Avancé +STR_3365 :{SMALLFONT}{BLACK}Autorise la sélection d'objets individuels du décor en plus des groupes de décor +STR_3366 :{BLACK}= Attraction +STR_3367 :{BLACK}= Stand de nourriture +STR_3368 :{BLACK}= Stand de boissons +STR_3369 :{BLACK}= Stand de souvenirs +STR_3370 :{BLACK}= Kiosque aux informations +STR_3371 :{BLACK}= Infirmerie +STR_3372 :{BLACK}= D.A.B. +STR_3373 :{BLACK}= Toilettes +STR_3374 :Attention : Trop d'objets sélectionnés ! +STR_3375 :Certains objets dans ce groupe de décor n'ont pas pu être sélectionnés +STR_3376 :Installer un nouveau modèle de circuit... +STR_3377 :{SMALLFONT}{BLACK}Installe un fichier qui contient un nouveau modèle de circuit +STR_3378 :Installer +STR_3379 :Annuler +STR_3380 :Impossible d'installer ce modèle de circuit... +STR_3381 :Le fichier n'est pas compatible ou contient des données invalides +STR_3382 :Copie du fichier échouée +STR_3383 :Sélectionnez le nouveau nom pour le modèle de circuit +STR_3384 :Un modèle de circuit possède déjà ce nom - Veuillez en choisir un autre pour celui ci : STR_3385 :Didacticiel pour débutants STR_3386 :Didacticiel attractions personnalisées STR_3387 :Didacticiel construction des montagnes russes -STR_3388 :Unable to switch to selected mode -STR_3389 :Unable to select additional item of scenery... -STR_3390 :Too many items selected +STR_3388 :Impossible de changer au mode sélectionné +STR_3389 :Impossible de choisir plus d'objets du décor... +STR_3390 :Trop d'objets sélectionnés STR_3391 :{SMALLFONT}{BLACK}Voici notre parc. Voyons ça d'un peu plus près... -STR_3392 :{SMALLFONT}{BLACK}Pour déplacer la vue, maintenir le bouton DROIT de la souris enfoncé puis bouger la souris... -STR_3393 :{SMALLFONT}{BLACK}Pour élargir la vue, faites un zomm arrière à l'aide de l'icone placé en haut de l'écran... +STR_3392 :{SMALLFONT}{BLACK}Pour déplacer la vue, maintenez le bouton DROIT de la souris enfoncé puis bouger la souris... +STR_3393 :{SMALLFONT}{BLACK}Pour élargir la vue, faites un zoom arrière à l'aide de l'icone placé en haut de l'écran... STR_3394 :{SMALLFONT}{BLACK}Vous pouvez aussi faire pivoter la vue par tranches de 90 degrés... STR_3395 :{SMALLFONT}{BLACK}Difficile d'entamer une construction avec une vue aussi large. Faites un zoom avant... STR_3396 :{SMALLFONT}{BLACK}Construisons d'abord une simple attraction... @@ -3409,44 +3409,205 @@ STR_3402 :{SMALLFONT}{BLACK}Bien, et si on ouvrait l'attraction maintenant ? STR_3403 :{SMALLFONT}{BLACK}Mais où sont passés les visiteurs ? STR_3404 :{SMALLFONT}{BLACK}Zut. Nous avons oublié d'ouvrir le parc. Bon il est temps d'y remédier... STR_3405 :{SMALLFONT}{BLACK}En attendant vos premiers visiteurs, occupons-nous du décor... -STR_3406 :{SMALLFONT}{BLACK}Here's our empty park. We're going to build a simple custom-designed ride... -STR_3407 :{SMALLFONT}{BLACK}First we need to choose a starting position... -STR_3408 :{SMALLFONT}{BLACK}The section of track we've just built is a 'station platform', to allow guests to get on and off the ride... -STR_3409 :{SMALLFONT}{BLACK}We'll extend the platform a bit by adding a couple more station platform sections... -STR_3410 :{SMALLFONT}{BLACK}The icons at the top of the construction window let you choose different track pieces to add... -STR_3411 :{SMALLFONT}{BLACK}We'll select a left-hand curve... -STR_3412 :{SMALLFONT}{BLACK}The curve hasn't been built yet, but the white ghost image shows where it will be built. Clicking the large 'build this' icon actually builds the track... -STR_3413 :{SMALLFONT}{BLACK}Now we want to build straight track, so we click the straight track icon... -STR_3414 :{SMALLFONT}{BLACK}Now that the circuit is complete, we need to build the ride entrance and exit... -STR_3415 :{SMALLFONT}{BLACK}Let's test our ride to check it works... -STR_3416 :{SMALLFONT}{BLACK}White it's being tested, we'll build the queue line and exit path... -STR_3417 :{SMALLFONT}{BLACK}OK - Let's open the park and the ride... -STR_3418 :{SMALLFONT}{BLACK}Our new ride isn't very exciting - Perhaps we should add some scenery? -STR_3419 :{SMALLFONT}{BLACK}To build scenery above other scenery or in mid-air, hold down the SHIFT key and move the mouse to select the height... -STR_3420 :{SMALLFONT}{BLACK}Some types of scenery can be re-painted after it's built... -STR_3421 :{SMALLFONT}{BLACK}Let's add some music to the ride... -STR_3422 :{SMALLFONT}{BLACK}Let's build a roller coaster ! -STR_3423 :{SMALLFONT}{BLACK}There are loads of pre-designed coasters, but we're going to build our own custom design... -STR_3424 :{SMALLFONT}{BLACK}That's the station platform built. Now we need a lift hill... -STR_3425 :{SMALLFONT}{BLACK}Roller coaster trains aren't powered, so a 'chain lift' is needed to pull the train up the first hill... -STR_3426 :{SMALLFONT}{BLACK}That's the lift hill complete - Now for the first drop... -STR_3427 :{SMALLFONT}{BLACK}Those curves are a bad idea - The riders will be flung to the sides by the lateral G forces as the train hurtles around... -STR_3428 :{SMALLFONT}{BLACK}Banking the curves will improve the ride - Riders will be pushed down into their seats instead of flung to the sides... -STR_3429 :{SMALLFONT}{BLACK}No - That won't work! Look at the height marks - The second hill is taller than the lift hill... -STR_3430 :{SMALLFONT}{BLACK}To ensure the train makes it around, each hill should be slightly smaller than the previous one... -STR_3431 :{SMALLFONT}{BLACK}That's better - Our train should make it up that hill now! Let's try some more twisted track... -STR_3432 :{SMALLFONT}{BLACK}We need to slow the train before the final curve and station, so let's add some brakes... -STR_3433 :{SMALLFONT}{BLACK}And finally we'll add 'block brakes', which allow two trains to operate more safely on the circuit... -STR_3434 :{SMALLFONT}{BLACK}Let's test the ride and see if it works! -STR_3435 :{SMALLFONT}{BLACK}Great - It worked! Let's add the footpaths and let guests onto our new roller coaster... -STR_3436 :{SMALLFONT}{BLACK}While waiting for our first riders, we could customize the ride a bit... -STR_3437 :{SMALLFONT}{BLACK}Clear large areas of scenery from landscape -STR_3438 :Unable to remove all scenery from here... +STR_3406 :{SMALLFONT}{BLACK}Voici notre parc vide. Nous allons construire une attraction simple et personnalisée... +STR_3407 :{SMALLFONT}{BLACK}Tout d'abord on doit choisir le point de départ... +STR_3408 :{SMALLFONT}{BLACK}La section du circuit que nous venons de construire est la 'station', cela permet aux visiteurs de monter et descendre de l'attraction... +STR_3409 :{SMALLFONT}{BLACK}Nous allons étendre cette station en ajoutant quelques blocs... +STR_3410 :{SMALLFONT}{BLACK}Les icônes en haut de la fenêtre de construction vous permet les différentes parties du circuit à ajouter... +STR_3411 :{SMALLFONT}{BLACK}Nous choissions une courbe vers la gauche... +STR_3412 :{SMALLFONT}{BLACK}La courbe n'est pas encore construite, mais l'image fantôme blanche indique où elle le sera. Cliquez sur l'icône 'construire ceci' pour construire le bloc... +STR_3413 :{SMALLFONT}{BLACK}Maintenant nous voulons construire un tracé droit, donc on clique sur l'icône 'tracé droit'... +STR_3414 :{SMALLFONT}{BLACK}Maintenant que le circuit est terminé, nous devons construire l'entrée et la sortie... +STR_3415 :{SMALLFONT}{BLACK}Testons notre attraction pour voir si tout va bien... +STR_3416 :{SMALLFONT}{BLACK}Pendant son test, on va construire la zone d'attente et l'allée de sortie... +STR_3417 :{SMALLFONT}{BLACK}OK - Ouvrons le parc et l'attraction... +STR_3418 :{SMALLFONT}{BLACK}Notre nouvelle attraction n'est pas très attractive - Peut-être que nous devons rajouter du décor ? +STR_3419 :{SMALLFONT}{BLACK}Pour construire du décor l'un au-dessus de l'autre ou en plein vol, maintenez la touche MAJ key et déplacez la souris pour choisir l'hauteur... +STR_3420 :{SMALLFONT}{BLACK}Certains éléments du décor peuvent être repeints après leur construction... +STR_3421 :{SMALLFONT}{BLACK}Ajoutons un peu de musique à notre attraction... +STR_3422 :{SMALLFONT}{BLACK}Construisons un montagne russe ! +STR_3423 :{SMALLFONT}{BLACK}Il y a plein de modèles pré-définis, mais nous allons construire notre propre circuit... +STR_3424 :{SMALLFONT}{BLACK}Voilà la station construite. Maintenant la montée... +STR_3425 :{SMALLFONT}{BLACK}Les trains des montagnes russes ne sont pas propulsés, une 'échelle' est nécessaire pour tirer le train lors de la première montée... +STR_3426 :{SMALLFONT}{BLACK}La montée est terminée - Maintenant la descente... +STR_3427 :{SMALLFONT}{BLACK}Ces courbes sont une mauvaise idée - Les visiteurs vont être projetés sur le côté de leur siège par les forces G latérales pendant que le train tourne... +STR_3428 :{SMALLFONT}{BLACK}Pencher les courbes améliorera l'attraction - Les visiteurs auront leur dos collé aux sièges plutôt que d'être projetés sur les côtés... +STR_3429 :{SMALLFONT}{BLACK}Non - Ca ne fonctionnera pas ! Regardez les marques de hauteur - La deuxième montée est plus grande que la première... +STR_3430 :{SMALLFONT}{BLACK}Pour être sûr que le train réussise le circuit, chaque montée doit être légèrement plus petite que la précédente... +STR_3431 :{SMALLFONT}{BLACK}C'est mieux - Notre train pourra passer cette montée ! Ajoutons des voies plus tordues... +STR_3432 :{SMALLFONT}{BLACK}Nous devons freiner le train avant la courbe finale et la station, ajoutons quelques freins... +STR_3433 :{SMALLFONT}{BLACK}Et finalement nous rajouterons des 'freins de blocs', cela permettra à 2 trains de parcourir le circuit en sécurité... +STR_3434 :{SMALLFONT}{BLACK}Testons l'attraction et regardons si tout fonctionne ! +STR_3435 :{SMALLFONT}{BLACK}Génial - Tout fonctionne ! Ajoutons la zone d'attente et l'allée de sortie pour que les visiteurs puissent y accéder... +STR_3436 :{SMALLFONT}{BLACK}En attendant les premiers passagers, on va personnaliser un peu l'attraction... +STR_3437 :{SMALLFONT}{BLACK}Nettoyer grande zone de décor du paysage +STR_3438 :Impossible d'effacer tout le décor d'içi... STR_3439 :Effacer décor STR_3440 :Page 1 STR_3441 :Page 2 STR_3442 :Page 3 STR_3443 :Page 4 STR_3444 :Page 5 -STR_3445 :Set Patrol Area -STR_3446 :Cancel Patrol Area +STR_3445 :Définir Zone de Patrouille +STR_3446 :Annuler Zone de Patrouille +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renouveler attr. +STR_5124 :Pas de Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +#Thousands separator +STR_5151 :. +#Decimal separator +STR_5152 :, +STR_5153 :Colour schemes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpaths +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear diff --git a/data/language/german.txt b/data/language/german.txt index 353879aed8..c22c41c6a5 100644 --- a/data/language/german.txt +++ b/data/language/german.txt @@ -3,97 +3,97 @@ # Use # at the beginning of a line to leave a comment. STR_0000 : STR_0001 :{STRINGID} {COMMA16} -STR_0002 :Bahn -STR_0003 :Bahn +STR_0002 :Spiral-Achterbahn +STR_0003 :Stehachterbahn STR_0004 :Schwingende Hängebahn -STR_0005 :Bahn +STR_0005 :Umgekehrte Achterbahn STR_0006 :Kinder-Achterbahn STR_0007 :Miniaturbahn STR_0008 :Einschienenbahn STR_0009 :Minihängebahn -STR_0010 :Bahn -STR_0011 :Bahn -STR_0012 :Bahn +STR_0010 :Bootsverleih +STR_0011 :Wilde Maus-Holzbahn +STR_0012 :Hindernislauf STR_0013 :Wagenbahn -STR_0014 :Bahn -STR_0015 :Bahn -STR_0016 :Bahn +STR_0014 :Hochgeschossener Freefall +STR_0015 :Bob-Achterbahn +STR_0016 :Aussichtsturm STR_0017 :Looping-Achterbahn -STR_0018 :Bahn -STR_0019 :Bahn +STR_0018 :Schlauchboot-Gleitbahn +STR_0019 :Minenachterbahn STR_0020 :Sessellift -STR_0021 :Bahn -STR_0022 :Bahn -STR_0023 :Bahn -STR_0024 :Bahn -STR_0025 :Bahn -STR_0026 :Bahn -STR_0027 :Bahn -STR_0028 :Bahn -STR_0029 :Bahn -STR_0030 :Stand -STR_0031 :Stand -STR_0032 :Stand -STR_0033 :Stand +STR_0021 :Korkenzieher-Achterbahn +STR_0022 :Irrgarten +STR_0023 :Spiralgleitbahn +STR_0024 :Go-Karts +STR_0025 :Wildwasserbahn +STR_0026 :Stromschnellen +STR_0027 :Autoskooter +STR_0028 :Piratenschiff +STR_0029 :Schwingendes Überkopfschiff +STR_0030 :Imbissstand +STR_0031 :Unbekannter Stand (1D) +STR_0032 :Getränkestand +STR_0033 :Unbekannter Stand (1F) STR_0034 :Stand -STR_0035 :Bahn +STR_0035 :Karussell STR_0036 :Stand STR_0037 :Kiosk STR_0038 :Toiletten -STR_0039 :Bahn -STR_0040 :Bahn -STR_0041 :Bahn -STR_0042 :Bahn -STR_0043 :Bahn +STR_0039 :Riesenrad +STR_0040 :Bewegungssimluator +STR_0041 :3D-Kino +STR_0042 :Top Spin +STR_0043 :Weltraumringe STR_0044 :Umgekehrte Freefall-Bahn STR_0045 :Lift -STR_0046 :Bahn -STR_0047 :Bahn -STR_0048 :Bahn -STR_0049 :Bahn -STR_0050 :Bahn -STR_0051 :Bahn -STR_0052 :Bahn -STR_0053 :Hyper-Twister-Achterbahn +STR_0046 :Vertikaler Fall Achterbahn +STR_0047 :Geldautomat +STR_0048 :Twist +STR_0049 :Spukhaus +STR_0050 :Erste Hilfe +STR_0051 :Zirkus +STR_0052 :Geisterbahn +STR_0053 :Twister-Achterbahn STR_0054 :Holzachterbahn -STR_0055 :Achterb. m. seitl. +STR_0055 :Achterbahn mit seitlicher Führung STR_0056 :Wilde Maus STR_0057 :Mehrdimensionale Achterbahn -STR_0058 :Bahn -STR_0059 :Umgekehrte Achterbahn -STR_0060 :Bahn -STR_0061 :Bahn -STR_0062 :Bahn -STR_0063 :Bahn -STR_0064 :Bahn +STR_0058 :Unbekannte Bahn (38) +STR_0059 :Fliegende Achterbahn +STR_0060 :Unbekannte Bahn (3A) +STR_0061 :Virginia Reel +STR_0062 :Splash-Boote +STR_0063 :Minihubschrauber +STR_0064 :Liegeachterbahn STR_0065 :Einschienenhängebahn -STR_0066 :Bahn -STR_0067 :Bahn +STR_0066 :Unbekannte Bahn (40) +STR_0067 :Umgekehrte Achterbahn STR_0068 :Heartline-Achterbahn -STR_0069 :Bahn -STR_0070 :Bahn -STR_0071 :Bahn -STR_0072 :Bahn -STR_0073 :Bahn -STR_0074 :Bahn -STR_0075 :Bahn +STR_0069 :Minigolf +STR_0070 :Giga-Bahn +STR_0071 :Roto-Drop +STR_0072 :Fliegende Untertassen +STR_0073 :Schiefes Haus +STR_0074 :Einschienenräder +STR_0075 :Kompakte umgekehrte Bahn STR_0076 :Wasserbahn -STR_0077 :Bahn -STR_0078 :Bahn -STR_0079 :Bahn -STR_0080 :Bahn -STR_0081 :Bahn -STR_0082 :Bahn -STR_0083 :Bahn -STR_0084 :Bahn -STR_0085 :Bahn -STR_0086 :Bahn -STR_0087 :Bahn -STR_0088 :Bahn +STR_0077 :Luftbetriebene Vertikalbahn +STR_0078 :Umgekehrte Haarnadelbahn +STR_0079 :Fliegender Teppich +STR_0080 :U-Boot-Fahrt +STR_0081 :Floße +STR_0082 :Unbekannte Bahn (50) +STR_0083 :Enterprise +STR_0084 :Unbekannte Bahn (52) +STR_0085 :Unbekannte Bahn (53) +STR_0086 :Unbekannte Bahn (54) +STR_0087 :Unbekannte Bahn (55) +STR_0088 :Umgekehrte Impuls-Bahn STR_0089 :Miniachterbahn -STR_0090 :Bahn -STR_0091 :Bahn -STR_0092 :Bahn +STR_0090 :Minenbahn +STR_0091 :Unbekannte Bahn (59) +STR_0092 :LIM Achterbahn STR_0093 : STR_0094 : STR_0095 : @@ -564,7 +564,7 @@ STR_0559 : STR_0560 : STR_0561 : STR_0562 : -STR_0563 :Die Fahrgäste sitzen in komfortablen Wagen mit einfachen Beckenhalterungen, in denen Sie gigantische, gemäßigte Gefälle erleben, aber auch viel Zeit oben `in der Luft' verbringen +STR_0563 :Die Fahrgäste sitzen in komfortablen Wagen mit einfachen Beckenhalterungen, in denen sie gigantische, gemäßigte Gefälle erleben, aber auch viel Zeit oben `in der Luft' verbringen STR_0564 :Diese Holzachterbahn ist schnell, rauh, laut und gibt einem das Gefühl, außer Kontrolle zu sein, wobei man häufig `in der Luft' ist STR_0565 :Eine einfache Holzachterbahn mit nur leichten Gefällen und Kurven, bei der die Wagen nur mit Hilfe von seitlichen Führungsrollen und der Schwerkraft auf der Strecke gehalten werden STR_0566 :Voneinander unabhängige Achterbahnwagen rasen auf einer engen Zickzack-Strecke mit scharfen Kurven und kurzen, starken Gefällen @@ -769,7 +769,7 @@ STR_0764 :Besucher {INT32} STR_0765 :Besucher {INT32} STR_0766 :Besucher {INT32} STR_0767 :Besucher {INT32} -STR_0768 :Handwerker {INT32} +STR_0768 :Parkpfleger {INT32} STR_0769 :Mechaniker {INT32} STR_0770 :Aufseher {INT32} STR_0771 :Animateur {INT32} @@ -857,7 +857,7 @@ STR_0852 :{WINDOW_COLOUR_2}Grafik von Simon Foster STR_0853 :{WINDOW_COLOUR_2}Sound und Musik von Allister Brimble STR_0854 :{WINDOW_COLOUR_2}Zusätzliche Sounds aufgenommen von David Ellis STR_0855 :{WINDOW_COLOUR_2}Repräsentation von Jacqui Lyons bei Marjacq Ltd. -STR_0856 :{WINDOW_COLOUR_2}Dank gilt:- +STR_0856 :{WINDOW_COLOUR_2}Dank gilt: STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth und John Wardley STR_0858 :{WINDOW_COLOUR_2} STR_0859 :{WINDOW_COLOUR_2} @@ -878,8 +878,8 @@ STR_0873 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} STR_0874 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} STR_0875 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} STR_0876 :{BLACK}{DOWN} -STR_0877 :Zu niedrig ! -STR_0878 :Zu hoch ! +STR_0877 :Zu niedrig! +STR_0878 :Zu hoch! STR_0879 :Gelände kann hier nicht tiefer gemacht werden... STR_0880 :Gelände kann hier nicht höher gemacht werden... STR_0881 :Objekt ist im Weg @@ -935,8 +935,8 @@ STR_0930 :S-Kurve (rechts) STR_0931 :Vert. Schleife (l.) STR_0932 :Vert. Schleife (r.) STR_0933 :Gelände zuerst höher bzw. niedriger machen -STR_0934 :Fahreingang im Weg -STR_0935 :Fahrausgang im Weg +STR_0934 :Attraktionseingang im Weg +STR_0935 :Attraktionsausgang im Weg STR_0936 :Parkeingang im Weg STR_0937 :{SMALLFONT}{BLACK}Ansichtsoptionen STR_0938 :{SMALLFONT}{BLACK}Landhöhe und -neigung anpassen @@ -946,7 +946,7 @@ STR_0941 :Vertikale Flächen entfernen STR_0942 :Bahnen ausblenden STR_0943 :Szenerie ausblenden STR_0944 :Speichern -STR_0945 :Nicht sp. +STR_0945 :Nicht speich. STR_0946 :Abbrechen STR_0947 :Vor dem Laden speichern? STR_0948 :Vor dem Beenden speichern? @@ -988,13 +988,13 @@ STR_0983 :Forschung & Entwicklung STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} STR_0986 :{BLACK}{CURRENCY2DP} -STR_0987 :Zu viele Bahnen/Attraktionen -STR_0988 :Neue Bahn/Attraktion kann nicht erstellt werden... +STR_0987 :Zu viele Attraktionen +STR_0988 :Neue Attraktion kann nicht erstellt werden... STR_0989 :{STRINGID} STR_0990 :{SMALLFONT}{BLACK}Konstruktion STR_0991 :Stationsplattform -STR_0992 :{SMALLFONT}{BLACK}Gesamte Bahn/Attraktion abreißen -STR_0993 :Bahn/Attraktion abreißen +STR_0992 :{SMALLFONT}{BLACK}Gesamte Attraktion abreißen +STR_0993 :Attraktion abreißen STR_0994 :Abreißen STR_0995 :{WINDOW_COLOUR_1}Soll {STRINGID} wirklich komplett abgerissen werden? STR_0996 :Gesamtansicht @@ -1003,19 +1003,19 @@ STR_0998 :Keine weiteren Stationen mehr bei dieser Bahn zulässig STR_0999 :Erfordert eine Stationsplattform STR_1000 :Strecke ist nicht in sich geschlossen STR_1001 :Strecke ist für diese Zugart ungeeignet -STR_1002 :Kann {POP16}{POP16}{POP16}{STRINGID} nicht eröffnen... +STR_1002 :Kann {POP16}{POP16}{POP16}{STRINGID} nicht öffnen... STR_1003 :Kann {POP16}{POP16}{POP16}{STRINGID} nicht testen... STR_1004 :Kann {POP16}{POP16}{POP16}{STRINGID} nicht schließen... STR_1005 :Kann {POP16}{POP16}{POP16}{STRINGID} nicht bauen... STR_1006 :Muss zuerst geschlossen werden STR_1007 :Es können nicht genügend Fahrzeuge erstellt werden -STR_1008 :{SMALLFONT}{BLACK}Bahn/Attraktion eröffnen, schließen oder testen -STR_1009 :{SMALLFONT}{BLACK}Alle Bahnen/Attraktionen eröffnen oder schließen -STR_1010 :{SMALLFONT}{BLACK}Park eröffnen oder schließen +STR_1008 :{SMALLFONT}{BLACK}Attraktion öffnen, schließen oder testen +STR_1009 :{SMALLFONT}{BLACK}Alle Attraktionen öffnen oder schließen +STR_1010 :{SMALLFONT}{BLACK}Park öffnen oder schließen STR_1011 :Alles schließen -STR_1012 :Alles eröffnen +STR_1012 :Alles öffnen STR_1013 :Park schließen -STR_1014 :Park eröffnen +STR_1014 :Park öffnen STR_1015 :Es kann nicht mehr als eine Stationsplattform in diesem Modus verwendet werden STR_1016 :Es können nicht weniger als zwei Stationsplattformen in diesem Modus verwendet werden STR_1017 :Betriebsmodus kann nicht geändert werden... @@ -1054,18 +1054,18 @@ STR_1049 :Speicherung der Landschaft fehlgeschlagen! STR_1050 :Konnte {NEWLINE} nicht laden. Datei enthält fehlerhafte Daten! STR_1051 :Unsichtbare Stützen STR_1052 :Unsichtbare Menschen -STR_1053 :{SMALLFONT}{BLACK}Bahnen/Attraktionen im Park -STR_1054 :{SMALLFONT}{BLACK}Bahn/Attraktion benennen +STR_1053 :{SMALLFONT}{BLACK}Attraktionen im Park +STR_1054 :{SMALLFONT}{BLACK}Attraktion benennen STR_1055 :{SMALLFONT}{BLACK}Person benennen STR_1056 :{SMALLFONT}{BLACK}Mitarbeiter benennen -STR_1057 :Name der Bahn/Attraktion -STR_1058 :Neuen Namen für diese Bahn/Attraktion eingeben:- -STR_1059 :Bahn/Attraktion kann nicht umbenannt werden... -STR_1060 :Ungültiger Bahn-/Attraktionsname +STR_1057 :Name der Attraktion +STR_1058 :Neuen Namen für diese Attraktion eingeben: +STR_1059 :Attraktion kann nicht umbenannt werden... +STR_1060 :Ungültiger Attraktionsname STR_1061 :Normaler Modus STR_1062 :Durchgängiger Rundenmodus -STR_1063 :Shuttle-Modus (Start bei umgek. Neig.) -STR_1064 :Angetriebener Start +STR_1063 :Shuttle-Modus (Start bei umgekehrter Neigung) +STR_1064 :Angetriebener Start (Station passieren) STR_1065 :Shuttle-Modus STR_1066 :Mietsboot-Modus STR_1067 :Aufwärtsstart @@ -1096,32 +1096,32 @@ STR_1091 :Zirkusmodus STR_1092 :Start nach unten STR_1093 :Schiefes Haus STR_1094 :Freefall-Modus -STR_1095 :Durchgängig. Streckenmodus m. Blockber. -STR_1096 :Angetriebener Start -STR_1097 :Modus mit angetrieb. Start u. Blockber. -STR_1098 :Geht ans Ende d. {POP16}{STRINGID} -STR_1099 :Warten auf Fahrgäste bei {POP16}{STRINGID} -STR_1100 :Wartet auf Abfahrt {POP16}{STRINGID} -STR_1101 :Abfahrt {POP16}{STRINGID} -STR_1102 :Fahrtgeschwindigkeit {VELOCITY} -STR_1103 :Ankunft bei {POP16}{STRINGID} -STR_1104 :Lädt Fahrgäste ab bei {POP16}{STRINGID} -STR_1105 :Fahrtgeschwindigkeit {VELOCITY} +STR_1095 :Durchgängiger Streckenmodus mit Blockbereichen +STR_1096 :Angetriebener Start (Station nicht passieren) +STR_1097 :Modus mit angetriebenem Start und Blockbereichen +STR_1098 :Fährt ans Ende der {POP16}{STRINGID} +STR_1099 :Wartet in {POP16}{STRINGID} auf Fahrgäste +STR_1100 :Wartet in {POP16}{STRINGID} auf Abfahrt +STR_1101 :Abfahrt aus {POP16}{STRINGID} +STR_1102 :Geschwindigkeit {VELOCITY} +STR_1103 :Ankunft in {POP16}{STRINGID} +STR_1104 :Lädt in {POP16}{STRINGID} Fahrgäste ab +STR_1105 :Geschwindigkeit {VELOCITY} STR_1106 :Unfall! STR_1107 :Verunglückt! -STR_1108 :Fahrtgeschwindigkeit {VELOCITY} -STR_1109 :Schwingen -STR_1110 :Rotation -STR_1111 :Rotation +STR_1108 :Geschwindigkeit {VELOCITY} +STR_1109 :Schwingt +STR_1110 :Rotiert +STR_1111 :Rotiert STR_1112 :In Betrieb STR_1113 :Film wird gezeigt -STR_1114 :Rotation +STR_1114 :Rotiert STR_1115 :In Betrieb STR_1116 :In Betrieb STR_1117 :Zirkus-Show im Gang STR_1118 :In Betrieb STR_1119 :Wartet auf Kabellift -STR_1120 :Fahrtgeschwindigkeit {VELOCITY} +STR_1120 :Geschwindigkeit {VELOCITY} STR_1121 :Stoppt STR_1122 :Wartet auf Fahrgäste STR_1123 :Wartet auf Start @@ -1142,18 +1142,18 @@ STR_1137 :{SMALLFONT}{BLACK}Zusatzfarbe 1 auswählen STR_1138 :{SMALLFONT}{BLACK}Zusatzfarbe 2 auswählen STR_1139 :{SMALLFONT}{BLACK}Farbe der Trägerstruktur auswählen STR_1140 :{SMALLFONT}{BLACK}Schemaoption für Fahrzeugfarbe auswählen -STR_1141 :{SMALLFONT}{BLACK}Zu modifizierendes Fahrzeug/Zug auswählen +STR_1141 :{SMALLFONT}{BLACK}Zu modifizierendes Fahrzeug auswählen STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} -STR_1144 :Eingang für diese Bahn/Attraktion kann nicht gebaut/verschoben werden... -STR_1145 :Ausgang für diese Bahn/Attraktion kann nicht gebaut/verschoben werden... +STR_1144 :Eingang für diese Attraktion kann nicht gebaut/verschoben werden... +STR_1145 :Ausgang für diese Attraktion kann nicht gebaut/verschoben werden... STR_1146 :Eingang noch nicht gebaut STR_1147 :Ausgang noch nicht gebaut -STR_1148 :Viertellast -STR_1149 :Halblast -STR_1150 :Dreiviertellast -STR_1151 :Volle Last -STR_1152 :Beliebige Last +STR_1148 :Viertelvoll +STR_1149 :Halbvoll +STR_1150 :Dreiviertelvoll +STR_1151 :Voll +STR_1152 :Beliebig STR_1153 :Höhenmarkierungen an Fahrstrecken STR_1154 :Höhenmarkierungen auf dem Gelände STR_1155 :Höhenmarkierungen an Fußwegen @@ -1198,7 +1198,7 @@ STR_1193 :{WINDOW_COLOUR_2}{STRINGID} STR_1194 :Geschlossen STR_1195 :Testlauf STR_1196 :Offen -STR_1197 :Baufällig/Kaputt +STR_1197 :Defekt STR_1198 :Verunglückt! STR_1199 :{COMMA16} Person auf Fahrt STR_1200 :{COMMA16} Personen auf Fahrt @@ -1209,14 +1209,14 @@ STR_1204 :{COMMA16} Minute Wartezeit STR_1205 :{COMMA16} Minuten Wartezeit STR_1206 :{WINDOW_COLOUR_2}Warten auf: STR_1207 :{WINDOW_COLOUR_2}Abfahren, wenn anderer Zug in Station ankommt -STR_1208 :{WINDOW_COLOUR_2}Abfahren, wenn ander. Boot in Station ankommt +STR_1208 :{WINDOW_COLOUR_2}Abfahren, wenn anderes Boot in Station ankommt STR_1209 :{SMALLFONT}{BLACK}Auswählen, ob vor Abfahrt auf Fahrgäste gewartet werden soll STR_1210 :{SMALLFONT}{BLACK}Auswählen, ob abgefahren werden soll, wenn anderes Fahrzeug in gleicher Station ankommt STR_1211 :{WINDOW_COLOUR_2}Mindestwartezeit: STR_1212 :{WINDOW_COLOUR_2}Höchstwartezeit: STR_1213 :{SMALLFONT}{BLACK}Wählen Sie die Mindestwartezeit vor der Abfahrt aus STR_1214 :{SMALLFONT}{BLACK}Wählen Sie die Höchstwartezeit vor der Abfahrt aus -STR_1215 :{WINDOW_COLOUR_2}Mit benachb. Stationen synchron. +STR_1215 :{WINDOW_COLOUR_2}Mit benachbarten Stationen synchronisieren STR_1216 :{SMALLFONT}{BLACK}Auswählen, ob Abfahrt mit allen benachbarten Stationen (für `Rennen') synchronisiert werden soll STR_1217 :{COMMA16} Sekunden STR_1218 :{BLACK}{SMALLUP} @@ -1328,9 +1328,9 @@ STR_1323 :Kurse STR_1324 :{COMMA16} Kurs STR_1325 :{COMMA16} Kurse STR_1326 :Kurs {COMMA16} -STR_1327 :{SMALLFONT}{BLACK}Objekte drehen um 90{DEGREE} +STR_1327 :{SMALLFONT}{BLACK}Objekte um 90{DEGREE} drehen STR_1328 :Ebenes Land erforderlich -STR_1329 :{WINDOW_COLOUR_2}Startgeschw.: +STR_1329 :{WINDOW_COLOUR_2}Startgeschwindigkeit: STR_1330 :{SMALLFONT}{BLACK}Höchstgeschwindigkeit beim Verlassen der Station STR_1331 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} STR_1332 :{VELOCITY} @@ -1341,23 +1341,23 @@ STR_1336 :{STRINGID} - Station {POP16}{COMMA16} Eingang STR_1337 :{STRINGID} - Ausgang{POP16}{POP16} STR_1338 :{STRINGID} - Station {POP16}{COMMA16} Ausgang STR_1339 :{BLACK}Noch keine Testergebnisse... -STR_1340 :{WINDOW_COLOUR_2}Max. Geschw: {BLACK}{VELOCITY} +STR_1340 :{WINDOW_COLOUR_2}Max. Geschwindigkeit: {BLACK}{VELOCITY} STR_1341 :{WINDOW_COLOUR_2}Fahrtdauer: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} STR_1342 :{DURATION} STR_1343 :{DURATION} / STR_1344 :{WINDOW_COLOUR_2}Fahrtlänge: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} STR_1345 :{LENGTH} STR_1346 :{LENGTH} / -STR_1347 :{WINDOW_COLOUR_2}Durchschn. G.: {BLACK}{VELOCITY} -STR_1348 :{WINDOW_COLOUR_2}Max. positive vertikale G-Kraft: {BLACK}{COMMA2DP32}G -STR_1349 :{WINDOW_COLOUR_2}Max. positive vertikale G-Kraft: {OUTLINE}{RED}{COMMA2DP32}G -STR_1350 :{WINDOW_COLOUR_2}Max. negative vertikale G-Kraft: {BLACK}{COMMA2DP32}G -STR_1351 :{WINDOW_COLOUR_2}Max. negative vertikale G-Kraft: {OUTLINE}{RED}{COMMA2DP32}G -STR_1352 :{WINDOW_COLOUR_2}Max. seitliche G-Kraft: {BLACK}{COMMA2DP32}G -STR_1353 :{WINDOW_COLOUR_2}Max. seitliche G-Kraft: {OUTLINE}{RED}{COMMA2DP32}G +STR_1347 :{WINDOW_COLOUR_2}Durchschn. Geschwindigkeit: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Max. positive vertikale G-Kraft: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}Max. positive vertikale G-Kraft: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}Max. negative vertikale G-Kraft: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}Max. negative vertikale G-Kraft: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}Max. seitliche G-Kraft: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}Max. seitliche G-Kraft: {OUTLINE}{RED}{COMMA2DP32}g STR_1354 :{WINDOW_COLOUR_2}Höchste Fallhöhe: {BLACK}{LENGTH} -STR_1355 :{WINDOW_COLOUR_2}Abf.: {BLACK}{COMMA16} -STR_1356 :{WINDOW_COLOUR_2}Umkehr.: {BLACK}{COMMA16} +STR_1355 :{WINDOW_COLOUR_2}Stürze: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Umkehrungen: {BLACK}{COMMA16} STR_1357 :{WINDOW_COLOUR_2}Löcher: {BLACK}{COMMA16} STR_1358 :{WINDOW_COLOUR_2}Gesamtzeit `in der Luft': {BLACK}{COMMA2DP32}Sek. STR_1359 :{WINDOW_COLOUR_2}Wartezeit: {BLACK}{COMMA16} Minute @@ -1393,7 +1393,7 @@ STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} STR_1389 :{OUTLINE}{RED}- {CURRENCY} STR_1390 :{CURRENCY2DP} STR_1391 :{RED}{CURRENCY2DP} -STR_1392 :{SMALLFONT}{BLACK}Ansicht der Bahn/Attraktion +STR_1392 :{SMALLFONT}{BLACK}Ansicht der Attraktion STR_1393 :{SMALLFONT}{BLACK}Fahrzeugdetails und -optionen STR_1394 :{SMALLFONT}{BLACK}Betriebsoptionen STR_1395 :{SMALLFONT}{BLACK}Wartungsoptionen @@ -1403,9 +1403,9 @@ STR_1398 :{SMALLFONT}{BLACK}Messungen und Testdaten STR_1399 :{SMALLFONT}{BLACK}Diagramme STR_1400 :Eingang STR_1401 :Ausgang -STR_1402 :{SMALLFONT}{BLACK}Eingang zur Bahn/Attraktion bauen oder verlegen -STR_1403 :{SMALLFONT}{BLACK}Ausgang von Bahn/Attraktion bauen oder verlegen -STR_1404 :{SMALLFONT}{BLACK}Drehen um 90{DEGREE} +STR_1402 :{SMALLFONT}{BLACK}Eingang zur Attraktion bauen oder verlegen +STR_1403 :{SMALLFONT}{BLACK}Ausgang von Attraktion bauen oder verlegen +STR_1404 :{SMALLFONT}{BLACK}Um 90{DEGREE} drehen STR_1405 :{SMALLFONT}{BLACK}Spiegelbild STR_1406 :{SMALLFONT}{BLACK}Szenerie ein-/ausschalten (falls für diesen Entwurf verfügbar) STR_1407 :{WINDOW_COLOUR_2}Dies bauen... @@ -1419,11 +1419,11 @@ STR_1414 :{SMALLFONT}{BLACK}{DURATION} STR_1415 :{WINDOW_COLOUR_2}Geschw. STR_1416 :{WINDOW_COLOUR_2}Höhe STR_1417 :{WINDOW_COLOUR_2}Vert. G -STR_1418 :{WINDOW_COLOUR_2}Seitl.G +STR_1418 :{WINDOW_COLOUR_2}Seitl. G STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} STR_1420 :{SMALLFONT}{BLACK}{LENGTH} -STR_1421 :{SMALLFONT}{BLACK}{COMMA16}G -STR_1422 :{SMALLFONT}{BLACK}Datenprotok. von {POP16}{STRINGID} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}Datenprotokoll von {POP16}{STRINGID} STR_1423 :{SMALLFONT}{BLACK}Warteschlangenweg STR_1424 :{SMALLFONT}{BLACK}Fußweg STR_1425 :Fußweg @@ -1432,9 +1432,9 @@ STR_1427 :{WINDOW_COLOUR_2}Besucher: {BLACK}{COMMA32} pro Stunde STR_1428 :{WINDOW_COLOUR_2}Eintrittspreis: STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} STR_1430 :Kostenlos -STR_1431 :Beim Gehen +STR_1431 :Geht STR_1432 :Geht Richtung {STRINGID} -STR_1433 :Steht in Schlange für {STRINGID} +STR_1433 :Steht Schlange für {STRINGID} STR_1434 :Ertrinkt STR_1435 :Auf {STRINGID} STR_1436 :In {STRINGID} @@ -1454,7 +1454,7 @@ STR_1449 :{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) STR_1450 :{INLINE_SPRITE}{09}{20}{00}{00}{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) STR_1451 :{STRINGID}{NEWLINE}({STRINGID}) STR_1452 :Name des Besuchers -STR_1453 :Namen für diesen Besucher eingeben:- +STR_1453 :Neuen Namen für diesen Besucher eingeben: STR_1454 :Besucher kann nicht benannt werden... STR_1455 :Ungültiger Name für Besucher STR_1456 :{WINDOW_COLOUR_2}Ausgegebenes Geld: {BLACK}{CURRENCY2DP} @@ -1481,7 +1481,7 @@ STR_1476 :{WINDOW_COLOUR_2}Intensitätswert: {BLACK}Noch nicht verfügbar STR_1477 :{WINDOW_COLOUR_2}Intensitätswert: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) STR_1478 :{WINDOW_COLOUR_2}Übelkeitswert: {BLACK}{COMMA2DP32} ({STRINGID}) STR_1479 :{WINDOW_COLOUR_2}Übelkeitswert: {BLACK}Noch nicht verfügbar -STR_1480 :{SMALLFONT}{OPENQUOTES}Ich kann mir d. {STRINGID} nicht leisten{ENDQUOTES} +STR_1480 :{SMALLFONT}{OPENQUOTES}Ich kann mir {STRINGID} nicht leisten{ENDQUOTES} STR_1481 :{SMALLFONT}{OPENQUOTES}Ich habe mein ganzes Geld ausgegeben{ENDQUOTES} STR_1482 :{SMALLFONT}{OPENQUOTES}Mir ist übel{ENDQUOTES} STR_1483 :{SMALLFONT}{OPENQUOTES}Mir ist total schlecht{ENDQUOTES} @@ -1489,29 +1489,29 @@ STR_1484 :{SMALLFONT}{OPENQUOTES}Ich will etwas Spannenderes als {STRINGID}{E STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} sieht mir zu extrem aus{ENDQUOTES} STR_1486 :{SMALLFONT}{OPENQUOTES}Ich bin noch nicht mit d. {STRINGID} fertig{ENDQUOTES} STR_1487 :{SMALLFONT}{OPENQUOTES}Uh, {STRINGID} - alleine beim Zusehen wird mir schlecht{ENDQUOTES} -STR_1488 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für f. {STRINGID}{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für {STRINGID}{ENDQUOTES} STR_1489 :{SMALLFONT}{OPENQUOTES}Ich will nach Hause{ENDQUOTES} STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} ist das Geld wirklich wert{ENDQUOTES} -STR_1491 :{SMALLFONT}{OPENQUOTES}Ich habe {STRINGID} bereits{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}Ich habe bereits {STRINGID}{ENDQUOTES} STR_1492 :{SMALLFONT}{OPENQUOTES}Ich kann mir d. {STRINGID} nicht leisten{ENDQUOTES} STR_1493 :{SMALLFONT}{OPENQUOTES}Ich bin nicht hungrig{ENDQUOTES} STR_1494 :{SMALLFONT}{OPENQUOTES}Ich bin nicht durstig{ENDQUOTES} STR_1495 :{SMALLFONT}{OPENQUOTES}Hilfe! Ich ertrinke!{ENDQUOTES} STR_1496 :{SMALLFONT}{OPENQUOTES}Ich habe mich verirrt!{ENDQUOTES} STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} war großartig{ENDQUOTES} -STR_1498 :{SMALLFONT}{OPENQUOTES}Ich habe für d. {STRINGID} ewig angestanden{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}Ich habe für {STRINGID} ewig angestanden{ENDQUOTES} STR_1499 :{SMALLFONT}{OPENQUOTES}Ich bin müde{ENDQUOTES} STR_1500 :{SMALLFONT}{OPENQUOTES}Ich bin hungrig{ENDQUOTES} STR_1501 :{SMALLFONT}{OPENQUOTES}Ich bin durstig{ENDQUOTES} STR_1502 :{SMALLFONT}{OPENQUOTES}Ich muss auf die Toilette{ENDQUOTES} -STR_1503 :{SMALLFONT}{OPENQUOTES}Ich kann d. {STRINGID} nicht finden{ENDQUOTES} -STR_1504 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für d. {STRINGID}{ENDQUOTES} -STR_1505 :{SMALLFONT}{OPENQUOTES}Ich gehe nicht auf d. {STRINGID}, solange es regnet{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}Ich kann {STRINGID} nicht finden{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}Ich gehe nicht auf {STRINGID}, solange es regnet{ENDQUOTES} STR_1506 :{SMALLFONT}{OPENQUOTES}Das Müllproblem ist hier wirklich extrem{ENDQUOTES} STR_1507 :{SMALLFONT}{OPENQUOTES}Ich kann den Parkausgang nicht finden{ENDQUOTES} -STR_1508 :{SMALLFONT}{OPENQUOTES}Ich möchte d. {STRINGID} verlassen{ENDQUOTES} -STR_1509 :{SMALLFONT}{OPENQUOTES}Ich möchte aus d. {STRINGID} aussteigen{ENDQUOTES} -STR_1510 :{SMALLFONT}{OPENQUOTES}Ich gehe nicht auf d. {STRINGID} - Es ist nicht sicher{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}Ich möchte {STRINGID} verlassen{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}Ich möchte aus {STRINGID} aussteigen{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}Ich gehe nicht auf {STRINGID} - Es ist nicht sicher{ENDQUOTES} STR_1511 :{SMALLFONT}{OPENQUOTES}Dieser Weg ist schrecklich{ENDQUOTES} STR_1512 :{SMALLFONT}{OPENQUOTES}Hier sind zu viele Leute{ENDQUOTES} STR_1513 :{SMALLFONT}{OPENQUOTES}Es sieht wirklich schlimm aus mit dem Vandalismus hier{ENDQUOTES} @@ -1526,7 +1526,7 @@ STR_1521 :{SMALLFONT}{OPENQUOTES}Dieses Fahrtfoto von {STRINGID} ist sein Gel STR_1522 :{SMALLFONT}{OPENQUOTES}Dieser Regenschirm von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1523 :{SMALLFONT}{OPENQUOTES}Dieses Getränk von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1524 :{SMALLFONT}{OPENQUOTES}Dieser Burger von {STRINGID} ist sein Geld wert{ENDQUOTES} -STR_1525 :{SMALLFONT}{OPENQUOTES}Diese Fritten von {STRINGID} sind ihr Geld wert{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}Diese Pommes von {STRINGID} sind ihr Geld wert{ENDQUOTES} STR_1526 :{SMALLFONT}{OPENQUOTES}Dieses Eis von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1527 :{SMALLFONT}{OPENQUOTES}Diese Zuckerwatte von {STRINGID} ist ihr Geld wert{ENDQUOTES} STR_1528 : @@ -1540,7 +1540,7 @@ STR_1535 :{SMALLFONT}{OPENQUOTES}Diese Meeresfrüchte von {STRINGID} sind ihr STR_1536 :{SMALLFONT}{OPENQUOTES}Dieser Hut von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1537 :{SMALLFONT}{OPENQUOTES}Dieser Karamellapfel von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1538 :{SMALLFONT}{OPENQUOTES}Dieses T-Shirt von {STRINGID} ist sein Geld wert{ENDQUOTES} -STR_1539 :{SMALLFONT}{OPENQUOTES}Dieser Doughnut von {STRINGID} ist sein Geld wert{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}Dieser Donut von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1540 :{SMALLFONT}{OPENQUOTES}Dieser Kaffee von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1541 : STR_1542 :{SMALLFONT}{OPENQUOTES}Dieses Brathähnchen von {STRINGID} ist sein Geld wert{ENDQUOTES} @@ -1560,7 +1560,7 @@ STR_1555 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für ein Fahrtfoto STR_1556 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Regenschirm von {STRINGID}{ENDQUOTES} STR_1557 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für ein Getränk von {STRINGID}{ENDQUOTES} STR_1558 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Ballon von {STRINGID}{ENDQUOTES} -STR_1559 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für Fritten von {STRINGID}{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für Pommes von {STRINGID}{ENDQUOTES} STR_1560 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für Eis von {STRINGID}{ENDQUOTES} STR_1561 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für Zuckerwatte von {STRINGID}{ENDQUOTES} STR_1562 : @@ -1574,7 +1574,7 @@ STR_1569 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für Meeresfrücht STR_1570 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Hut von {STRINGID}{ENDQUOTES} STR_1571 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Karamellapfel von {STRINGID}{ENDQUOTES} STR_1572 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für ein T-Shirt von {STRINGID}{ENDQUOTES} -STR_1573 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Doughnut von {STRINGID}{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Donut von {STRINGID}{ENDQUOTES} STR_1574 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Kaffee von {STRINGID}{ENDQUOTES} STR_1575 : STR_1576 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für ein Brathähnchen von {STRINGID}{ENDQUOTES} @@ -1588,7 +1588,7 @@ STR_1583 : STR_1584 :{SMALLFONT}{OPENQUOTES}Dieses Fahrtfoto von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1585 :{SMALLFONT}{OPENQUOTES}Dieses Fahrtfoto von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1586 :{SMALLFONT}{OPENQUOTES}Dieses Fahrtfoto von {STRINGID} ist sein Geld wert{ENDQUOTES} -STR_1587 :{SMALLFONT}{OPENQUOTES}Diese Bretzel von {STRINGID} ist ihr Geld wert{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}Diese Brezel von {STRINGID} ist ihr Geld wert{ENDQUOTES} STR_1588 :{SMALLFONT}{OPENQUOTES}Diese heiße Schokolade von {STRINGID} ist ihr Geld wert{ENDQUOTES} STR_1589 :{SMALLFONT}{OPENQUOTES}Dieser Eistee von {STRINGID} ist sein Geld wert{ENDQUOTES} STR_1590 :{SMALLFONT}{OPENQUOTES}Dieser Kuchen von {STRINGID} ist sein Geld wert{ENDQUOTES} @@ -1620,7 +1620,7 @@ STR_1615 : STR_1616 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für ein Fahrtfoto von {STRINGID}{ENDQUOTES} STR_1617 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für ein Fahrtfoto von {STRINGID}{ENDQUOTES} STR_1618 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für ein Fahrtfoto von {STRINGID}{ENDQUOTES} -STR_1619 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für eine Bretzel von {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für eine Brezel von {STRINGID}{ENDQUOTES} STR_1620 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für eine heiße Schokolade von {STRINGID}{ENDQUOTES} STR_1621 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Eistee von {STRINGID}{ENDQUOTES} STR_1622 :{SMALLFONT}{OPENQUOTES}Ich bezahle nicht so viel für einen Kuchen von {STRINGID}{ENDQUOTES} @@ -1658,10 +1658,10 @@ STR_1653 :{SMALLFONT}{OPENQUOTES}...und hier sind wir bei d. {STRINGID}!{ENDQ STR_1654 :{WINDOW_COLOUR_2}Aktuelle Gedanken: STR_1655 :{SMALLFONT}{BLACK}Fußweg auf Gelände anlegen STR_1656 :{SMALLFONT}{BLACK}Brücke bauen oder Tunnelfußweg anlegen -STR_1657 :{WINDOW_COLOUR_2}Bevorzugte Bahn -STR_1658 :{WINDOW_COLOUR_2}Intensität: {BLACK}weniger als {COMMA16} -STR_1659 :{WINDOW_COLOUR_2}Intensität: {BLACK}zwischen {COMMA16} und {COMMA16} -STR_1660 :{WINDOW_COLOUR_2}Intensität: {BLACK}mehr als {COMMA16} +STR_1657 :{WINDOW_COLOUR_2}Bevorzugte Bahn- +STR_1658 :{WINDOW_COLOUR_2}intensität: {BLACK}weniger als {COMMA16} +STR_1659 :{WINDOW_COLOUR_2}intensität: {BLACK}zwischen {COMMA16} und {COMMA16} +STR_1660 :{WINDOW_COLOUR_2}intensität: {BLACK}mehr als {COMMA16} STR_1661 :{WINDOW_COLOUR_2}Übelkeitstoleranz: {BLACK}{STRINGID} STR_1662 :{WINDOW_COLOUR_2}Vergnügen: STR_1663 :{WINDOW_COLOUR_2}Übelkeit: @@ -1675,7 +1675,7 @@ STR_1670 :{WINDOW_COLOUR_2}Besucher gesamt: {BLACK}{COMMA32} STR_1671 :{WINDOW_COLOUR_2}Gesamtgewinn: {BLACK}{CURRENCY2DP} STR_1672 :Bremsen STR_1673 :Drehkontrolle umschalten -STR_1674 :Bremsgeschw. +STR_1674 :Bremsgeschwindigkeit STR_1675 :{POP16}{VELOCITY} STR_1676 :{SMALLFONT}{BLACK}Geschwindigkeitsgrenze für Bremsen einstellen STR_1677 :{WINDOW_COLOUR_2}Popularität: {BLACK}Unbekannt @@ -1693,7 +1693,7 @@ STR_1688 :Grundflächengröße 4 x 1 STR_1689 :Klotzbremsen STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} STR_1691 :{WINDOW_COLOUR_2} Kosten: {BLACK}{CURRENCY} -STR_1692 :{WINDOW_COLOUR_2} Kosten: {BLACK}von {CURRENCY} +STR_1692 :{WINDOW_COLOUR_2} Kosten: {BLACK}ab {CURRENCY} STR_1693 :{SMALLFONT}{BLACK}Besucher STR_1694 :{SMALLFONT}{BLACK}Personal STR_1695 :{SMALLFONT}{BLACK}Einkünfte und Kosten @@ -1701,8 +1701,8 @@ STR_1696 :{SMALLFONT}{BLACK}Besucherinformationen STR_1697 :Können nicht in Wartebereich platziert werden STR_1698 :Können nur in Wartebereich platziert werden STR_1699 :Zu viele Leute im Spiel -STR_1700 :Neuen Handwerker einstellen -STR_1701 :Neuen Mechaniker einstellen +STR_1700 :Neuen Parkpfleger einst. +STR_1701 :Neuen Mechaniker einst. STR_1702 :Neuen Aufseher einstellen STR_1703 :Neuen Animateur einstellen STR_1704 :Es kann kein neuer Mitarbeiter eingestellt werden... @@ -1720,10 +1720,10 @@ STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Gras mähen STR_1716 :Ungültiger Name für Park STR_1717 :Park kann nicht umbenannt werden... STR_1718 :Parkname -STR_1719 :Geben Sie einen Parknamen ein:- +STR_1719 :Geben Sie einen Parknamen ein: STR_1720 :{SMALLFONT}{BLACK}Park benennen STR_1721 :Park geschlossen -STR_1722 :Park eröffnet +STR_1722 :Park geöffnet STR_1723 :Park kann nicht eröffnet werden... STR_1724 :Park kann nicht geschlossen werden... STR_1725 :Land kann nicht gekauft werden... @@ -1735,14 +1735,14 @@ STR_1730 :{RED}Geschlossen - - STR_1731 :{WHITE}{STRINGID} - - STR_1732 :Bauen STR_1733 :Modus -STR_1734 :{WINDOW_COLOUR_2}Anzahl d. Runden: +STR_1734 :{WINDOW_COLOUR_2}Anzahl der Runden: STR_1735 :{SMALLFONT}{BLACK}Rundenanzahl der Rundfahrt STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1737 :{COMMA16} STR_1738 :Rundenanzahl kann nicht geändert werden... STR_1739 :Rennen gewonnen von Besucher {INT32} STR_1740 :Rennen wurde gewonnen von {STRINGID} -STR_1741 :Noch nicht gebaut ! +STR_1741 :Noch nicht gebaut! STR_1742 :{WINDOW_COLOUR_2}Max. Besucherzahl: STR_1743 :{SMALLFONT}{BLACK}Höchstzahl zulässiger Personen zu einem Zeitpunkt bei dieser Bahn STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} @@ -1778,7 +1778,7 @@ STR_1773 :Nur ein Fahrtfoto-Bereich pro Bahn erlaubt STR_1774 :Nur ein Kabellifthügel pro Bahn erlaubt STR_1775 :Aus STR_1776 :Ein -STR_1777 :{WINDOW_COLOUR_2}Musik: +STR_1777 :{WINDOW_COLOUR_2}Musik STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Pandakostüm STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigerkostüm @@ -1801,12 +1801,12 @@ STR_1796 :Ist ausgefallen und erfordert Reparatur STR_1797 :Diese Option kann für diese Bahn nicht geändert werden STR_1798 :Whirlpool STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} -STR_1800 :Sicherung -STR_1801 :Halt. klemmen (offen) -STR_1802 :Halt. klemmen (geschl.) -STR_1803 :Türen klemmen (geschl.) -STR_1804 :Türen klemmen (offen) -STR_1805 :Fahrzeugfehlfunktion +STR_1800 :Sicherheitsabschaltung +STR_1801 :Sicherheitsbügel öffnen nicht +STR_1802 :Sicherheitsbügel schließen nicht +STR_1803 :Türen öffnen nicht +STR_1804 :Türen schließen nicht +STR_1805 :Fehlfunktion des Fahrzeugs STR_1806 :Stationsbremsen defekt STR_1807 :Kontrolle defekt STR_1808 :{WINDOW_COLOUR_2}Letzte Störung: {BLACK}{STRINGID} @@ -1824,9 +1824,9 @@ STR_1819 :{WINDOW_COLOUR_2}Alle Besucher (zusammengefasst) STR_1820 :{WINDOW_COLOUR_2}Besucher {STRINGID} STR_1821 :{WINDOW_COLOUR_2}Besucher denken {STRINGID} STR_1822 :{WINDOW_COLOUR_2}Besucher denken an {POP16}{STRINGID} -STR_1823 :{SMALLFONT}{BLACK}Gedanken der Besucher zu dieser Bahn/Attraktion anzeigen -STR_1824 :{SMALLFONT}{BLACK}Besucher dieser Bahn/Attraktion anzeigen -STR_1825 :{SMALLFONT}{BLACK}Anstehende Besucher für diese Bahn/Attraktion anzeigen +STR_1823 :{SMALLFONT}{BLACK}Gedanken der Besucher zu dieser Attraktion anzeigen +STR_1824 :{SMALLFONT}{BLACK}Besucher dieser Attraktion anzeigen +STR_1825 :{SMALLFONT}{BLACK}Anstehende Besucher für diese Attraktion anzeigen STR_1826 :Status STR_1827 :Popularität STR_1828 :Zufriedenheit @@ -1842,10 +1842,10 @@ STR_1837 :Zufriedenheit: Unbekannt STR_1838 :Zufriedenheit: {COMMA16}% STR_1839 :Zuverlässigkeit: {COMMA16}% STR_1840 :Ausfallzeit: {COMMA16}% -STR_1841 :Gewinn: {CURRENCY} pro Stunde +STR_1841 :Gewinn: {CURRENCY2DP} pro Stunde STR_1842 :Favorit von: {COMMA16} Besucher STR_1843 :Favorit von: {COMMA16} Besuchern -STR_1844 :{SMALLFONT}{BLACK}Informationsart auswählen, die in Bahn-/Attraktionsliste angezeigt werden soll +STR_1844 :{SMALLFONT}{BLACK}Informationsart auswählen, die in Attraktionsliste angezeigt werden soll STR_1845 :{MONTHYEAR} STR_1846 :{COMMA16} Besucher STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} Besucher @@ -1854,28 +1854,28 @@ STR_1849 :{WINDOW_COLOUR_2}Musikwiedergabe STR_1850 :{SMALLFONT}{BLACK}Auswählen, ob Musik für diese Bahn abgespielt werden soll STR_1851 :{WINDOW_COLOUR_2}Betriebskosten: {BLACK}{CURRENCY2DP} pro Stunde STR_1852 :{WINDOW_COLOUR_2}Betriebskosten: {BLACK}Unbekannt -STR_1853 :{WINDOW_COLOUR_2}Baudatum: {BLACK}Dieses Jahr -STR_1854 :{WINDOW_COLOUR_2}Baudatum: {BLACK}Letztes Jahr -STR_1855 :{WINDOW_COLOUR_2}Baudatum: Vor {BLACK}{COMMA16} Jahren -STR_1856 :{WINDOW_COLOUR_2}Gewinn pro verkaufter Artikel: {BLACK}{CURRENCY2DP} -STR_1857 :{WINDOW_COLOUR_2}Verlust pro verkaufter Artikel: {BLACK}{CURRENCY2DP} -STR_1858 :{WINDOW_COLOUR_2}Kosten: {BLACK}{CURRENCY} pro Monat -STR_1859 :Handwerker +STR_1853 :{WINDOW_COLOUR_2}Erbaut: {BLACK}Dieses Jahr +STR_1854 :{WINDOW_COLOUR_2}Erbaut: {BLACK}Letztes Jahr +STR_1855 :{WINDOW_COLOUR_2}Erbaut: {BLACK}Vor {COMMA16} Jahren +STR_1856 :{WINDOW_COLOUR_2}Gewinn pro verkauftem Artikel: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Verlust pro verkauftem Artikel: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}Kosten: {BLACK}{CURRENCY2DP} pro Monat +STR_1859 :Parkpfleger STR_1860 :Mechaniker STR_1861 :Aufseher STR_1862 :Animateur -STR_1863 :Handwerker +STR_1863 :Parkpfleger STR_1864 :Mechaniker STR_1865 :Aufseher STR_1866 :Animateur STR_1867 :{BLACK}{COMMA16} {STRINGID} STR_1868 :Anzahl der Drehungen kann nicht geändert werden... -STR_1869 :{WINDOW_COLOUR_2}Anzahl d. Drehungen: +STR_1869 :{WINDOW_COLOUR_2}Anzahl der Drehungen: STR_1870 :{SMALLFONT}{BLACK}Anzahl kompletter Drehungen STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1872 :{COMMA16} -STR_1873 :{WINDOW_COLOUR_2}Einkünfte: {BLACK}{CURRENCY} pro Stunde -STR_1874 :{WINDOW_COLOUR_2}Gewinn: {BLACK}{CURRENCY} pro Stunde +STR_1873 :{WINDOW_COLOUR_2}Einkünfte: {BLACK}{CURRENCY2DP} pro Stunde +STR_1874 :{WINDOW_COLOUR_2}Gewinn: {BLACK}{CURRENCY2DP} pro Stunde STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Bahnen inspizieren STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Bahnen reparieren @@ -1894,15 +1894,15 @@ STR_1889 :{WINDOW_COLOUR_2}Ausfallzeit: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Auswählen, wie oft ein Mechaniker diese Bahn überprüfen soll STR_1891 :Noch kein {STRINGID} im Park STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Legen Sie die RollerCoaster Tycoon 2-CD in folgendes Laufwerk ein:- +STR_1893 :Legen Sie die RollerCoaster Tycoon 2-CD in folgendes Laufwerk ein: STR_1894 :{WINDOW_COLOUR_2}{STRINGID} verkauft: {BLACK}{COMMA32} -STR_1895 :{SMALLFONT}{BLACK}Neue Bahn/Attraktion bauen +STR_1895 :{SMALLFONT}{BLACK}Neue Attraktion bauen STR_1896 :{WINDOW_COLOUR_2}Ausgaben/Einnahmen STR_1897 :{WINDOW_COLOUR_2}Bahnkonstruktion STR_1898 :{WINDOW_COLOUR_2}Bahnbetriebskosten STR_1899 :{WINDOW_COLOUR_2}Landerwerb STR_1900 :{WINDOW_COLOUR_2}Landschaftsgestaltung -STR_1901 :{WINDOW_COLOUR_2}Parkeintrittstickets +STR_1901 :{WINDOW_COLOUR_2}Parkeintrittskarten STR_1902 :{WINDOW_COLOUR_2}Bahntickets STR_1903 :{WINDOW_COLOUR_2}Ladenverkäufe STR_1904 :{WINDOW_COLOUR_2}Ladenvorrat @@ -1917,7 +1917,7 @@ STR_1912 :{MONTH} STR_1913 :{BLACK}+{CURRENCY2DP} STR_1914 :{BLACK}{CURRENCY2DP} STR_1915 :{RED}{CURRENCY2DP} -STR_1916 :{WINDOW_COLOUR_2}Darleh.: +STR_1916 :{WINDOW_COLOUR_2}Darlehen: STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} STR_1918 :Es können keine weiteren Gelder geliehen werden! STR_1919 :Nicht genügend Geld verfügbar! @@ -1929,7 +1929,7 @@ STR_1924 :{SMALLFONT}{BLACK}Beenden STR_1925 :Person kann hier nicht platziert werden... STR_1926 :{SMALLFONT} STR_1927 :{YELLOW}{STRINGID} ist ausgefallen -STR_1928 :{RED}{STRINGID} hat Unfall! +STR_1928 :{RED}{STRINGID} hatte einen Unfall! STR_1929 :{RED}{STRINGID} wurde immer noch nicht repariert{NEWLINE}Schauen Sie nach, wo Ihre Mechaniker sind, und organisieren Sie sie besser STR_1930 :{SMALLFONT}{BLACK}Überwachungsinformationen zu diesem Besucher ein-/ausschalten - (Bei eingeschalteter Überwachung werden Besucheraktivitäten im Nachrichtenbereich angezeigt) STR_1931 :{STRINGID} steht an für {STRINGID} @@ -1968,7 +1968,7 @@ STR_1963 :{WINDOW_COLOUR_2}Fahrtfotopreis: STR_1964 :{WINDOW_COLOUR_2}Regenschirmpreis: STR_1965 :{WINDOW_COLOUR_2}Getränkepreis: STR_1966 :{WINDOW_COLOUR_2}Burgerpreis: -STR_1967 :{WINDOW_COLOUR_2}Frittenpreis: +STR_1967 :{WINDOW_COLOUR_2}Pommespreis: STR_1968 :{WINDOW_COLOUR_2}Eispreis: STR_1969 :{WINDOW_COLOUR_2}Zuckerwattepreis: STR_1970 :{WINDOW_COLOUR_2} @@ -1982,7 +1982,7 @@ STR_1977 :{WINDOW_COLOUR_2}Meeresfrüchtepreis: STR_1978 :{WINDOW_COLOUR_2}Hutpreis: STR_1979 :{WINDOW_COLOUR_2}Karamellapfelpreis: STR_1980 :{WINDOW_COLOUR_2}T-Shirt-Preis: -STR_1981 :{WINDOW_COLOUR_2}Doughnut-Preis: +STR_1981 :{WINDOW_COLOUR_2}Donut-Preis: STR_1982 :{WINDOW_COLOUR_2}Kaffeepreis: STR_1983 :{WINDOW_COLOUR_2} STR_1984 :{WINDOW_COLOUR_2}Brathähnchenpreis: @@ -1996,7 +1996,7 @@ STR_1991 :Fahrtfoto STR_1992 :Regenschirm STR_1993 :Getränk STR_1994 :Burger -STR_1995 :Fritten +STR_1995 :Pommes STR_1996 :Eis STR_1997 :Zuckerwatte STR_1998 :Leere Dose @@ -2010,7 +2010,7 @@ STR_2005 :Meeresfrüchte STR_2006 :Hut STR_2007 :Karamellapfel STR_2008 :T-Shirt -STR_2009 :Doughnut +STR_2009 :Donut STR_2010 :Kaffee STR_2011 :Leere Tasse STR_2012 :Brathähnchen @@ -2024,7 +2024,7 @@ STR_2019 :Fahrtfotos STR_2020 :Regenschirme STR_2021 :Getränke STR_2022 :Burger -STR_2023 :Fritten +STR_2023 :Pommes STR_2024 :Eis STR_2025 :Zuckerwatte STR_2026 :Leere Dosen @@ -2038,7 +2038,7 @@ STR_2033 :Meeresfrüchte STR_2034 :Hüte STR_2035 :Karamelläpfel STR_2036 :T-Shirts -STR_2037 :Doughnuts +STR_2037 :Donuts STR_2038 :Kaffees STR_2039 :Leere Tassen STR_2040 :Brathähnchen @@ -2052,7 +2052,7 @@ STR_2047 :ein Fahrtfoto STR_2048 :einen Regenschirm STR_2049 :ein Getränk STR_2050 :einen Burger -STR_2051 :Fritten +STR_2051 :Pommes STR_2052 :Eis STR_2053 :Zuckerwatte STR_2054 :eine leere Dose @@ -2066,7 +2066,7 @@ STR_2061 :Meeresfrüchte STR_2062 :einen Hut STR_2063 :einen Karamellapfel STR_2064 :ein T-Shirt -STR_2065 :einen Doughnut +STR_2065 :einen Donut STR_2066 :einen Kaffee STR_2067 :eine leere Tasse STR_2068 :ein Brathähnchen @@ -2080,7 +2080,7 @@ STR_2075 :Fahrtfoto von {STRINGID} STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Regenschirm STR_2077 :Getränk STR_2078 :Burger -STR_2079 :Fritten +STR_2079 :Pommes STR_2080 :Eis STR_2081 :Zuckerwatte STR_2082 :Leere Dose @@ -2094,7 +2094,7 @@ STR_2089 :Meeresfrüchte STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hut STR_2091 :Karamellapfel STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt -STR_2093 :Doughnut +STR_2093 :Donut STR_2094 :Kaffee STR_2095 :Leere Tasse STR_2096 :Brathähnchen @@ -2104,8 +2104,8 @@ STR_2099 :Leere Flasche STR_2100 :{WINDOW_COLOUR_2}Fahrtfotopreis: STR_2101 :{WINDOW_COLOUR_2}Fahrtfotopreis: STR_2102 :{WINDOW_COLOUR_2}Fahrtfotopreis: -STR_2103 :{WINDOW_COLOUR_2}Bretzelpreis: -STR_2104 :{WINDOW_COLOUR_2}Preis f. heiße Schokol.: +STR_2103 :{WINDOW_COLOUR_2}Brezelpreis: +STR_2104 :{WINDOW_COLOUR_2}Preis für heiße Schokol.: STR_2105 :{WINDOW_COLOUR_2}Eisteepreis: STR_2106 :{WINDOW_COLOUR_2}Kuchenpreis: STR_2107 :{WINDOW_COLOUR_2}Sonnenbrillenpreis: @@ -2126,7 +2126,7 @@ STR_2121 :{WINDOW_COLOUR_2} STR_2122 :Fahrtfoto STR_2123 :Fahrtfoto STR_2124 :Fahrtfoto -STR_2125 :Bretzel +STR_2125 :Brezel STR_2126 :Heiße Schokolade STR_2127 :Eistee STR_2128 :Kuchen @@ -2148,7 +2148,7 @@ STR_2143 :Leere Schüssel STR_2144 :Fahrtfotos STR_2145 :Fahrtfotos STR_2146 :Fahrtfotos -STR_2147 :Bretzeln +STR_2147 :Brezeln STR_2148 :Heiße Schokolade STR_2149 :Eistees STR_2150 :Kuchen @@ -2170,7 +2170,7 @@ STR_2165 :Leere Schüsseln STR_2166 :ein Fahrtfoto STR_2167 :ein Fahrtfoto STR_2168 :ein Fahrtfoto -STR_2169 :eine Bretzel +STR_2169 :eine Brezel STR_2170 :eine heiße Schokolade STR_2171 :ein Eistee STR_2172 :ein Kuchen @@ -2192,7 +2192,7 @@ STR_2187 :eine leere Schüssel STR_2188 :Fahrtfoto von {STRINGID} STR_2189 :Fahrtfoto von {STRINGID} STR_2190 :Fahrtfoto von {STRINGID} -STR_2191 :Bretzel +STR_2191 :Brezel STR_2192 :Heiße Schokolade STR_2193 :Eistee STR_2194 :Kuchen @@ -2211,7 +2211,7 @@ STR_2206 :Leerer Getränkekarton STR_2207 :Leeres Saftglas STR_2208 :Bratwurst STR_2209 :Leere Schüssel -STR_2210 :{SMALLFONT}{BLACK}Liste der Handwerker im Park anzeigen +STR_2210 :{SMALLFONT}{BLACK}Liste der Parkpfleger im Park anzeigen STR_2211 :{SMALLFONT}{BLACK}Liste der Mechaniker im Park anzeigen STR_2212 :{SMALLFONT}{BLACK}Liste der Aufseher im Park anzeigen STR_2213 :{SMALLFONT}{BLACK}Liste der Animateure im Park anzeigen @@ -2249,9 +2249,9 @@ STR_2244 :September STR_2245 :Oktober STR_2246 :November STR_2247 :Dezember -STR_2248 :Bahn/Attraktion kann nicht abgerissen werden... -STR_2249 :{BABYBLUE}Neue Bahn/Attraktion jetzt verfügbar:-{NEWLINE}{STRINGID} -STR_2250 :{BABYBLUE}Neue/s/r Szenerie/Thema jetzt verfügbar:-{NEWLINE}{STRINGID} +STR_2248 :Attraktion kann nicht abgerissen werden... +STR_2249 :{BABYBLUE}Neue Attraktion jetzt verfügbar:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}Neue Szenerie jetzt verfügbar:{NEWLINE}{STRINGID} STR_2251 :Kann nur auf Wegen gebaut werden! STR_2252 :Kann nur über Wege gebaut werden! STR_2253 :Transportbahnen @@ -2262,8 +2262,8 @@ STR_2257 :Wasserbahnen STR_2258 :Läden & Stände STR_2259 :Szenerie & Thema STR_2260 :Keine Finanzierung -STR_2261 :Mindestfinanzier. -STR_2262 :Normale Finanzier. +STR_2261 :Mindestfinanzierung +STR_2262 :Normale Finanzierung STR_2263 :Höchstfinanzierung STR_2264 :Forschungsfinanzierung STR_2265 :{WINDOW_COLOUR_2}Kosten: {BLACK}{CURRENCY} pro Monat @@ -2273,7 +2273,7 @@ STR_2268 :Letzte Entwicklung STR_2269 :{WINDOW_COLOUR_2}Typ: {BLACK}{STRINGID} STR_2270 :{WINDOW_COLOUR_2}Fortschritt: {BLACK}{STRINGID} STR_2271 :{WINDOW_COLOUR_2}Erwartet: {BLACK}{STRINGID} -STR_2272 :{WINDOW_COLOUR_2}Bahn/Attraktion:{NEWLINE}{BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Attraktion:{NEWLINE}{BLACK}{STRINGID} STR_2273 :{WINDOW_COLOUR_2}Szenerie/Thema:{NEWLINE}{BLACK}{STRINGID} STR_2274 :{SMALLFONT}{BLACK}Details zu dieser Erfindung bzw. Entwicklung anzeigen STR_2275 :{SMALLFONT}{BLACK}Finanzierung und Optionen für Forschung & Entwicklung anzeigen @@ -2297,7 +2297,7 @@ STR_2292 :{WINDOW_COLOUR_2}Fahrten auf: STR_2293 :{BLACK} Nichts STR_2294 :{SMALLFONT}{BLACK}Grundflächenstil ändern STR_2295 :{SMALLFONT}{BLACK}Vertikale Ränder des Geländes ändern -STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} bez. um in Park zu gehen +STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} bezahlt um in Park zu gehen STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} ausgegeben für {BLACK}{COMMA16} Fahrt STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} ausgegeben für {BLACK}{COMMA16} Fahrten STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} ausgegeben für {BLACK}{COMMA16} Speiseartikel @@ -2312,17 +2312,17 @@ STR_2307 :Entwurf {STRINGID} auswählen STR_2308 :{STRINGID} Streckenentwürfe STR_2309 :Neuen Streckenentwurf installieren STR_2310 :Nach eigenem Entwurf bauen -STR_2311 :{WINDOW_COLOUR_2}Nervenkitzelwert: {BLACK}{COMMA2DP32} (ungef.) -STR_2312 :{WINDOW_COLOUR_2}Intensitätswert: {BLACK}{COMMA2DP32} (ungef.) -STR_2313 :{WINDOW_COLOUR_2}Übelkeitswert: {BLACK}{COMMA2DP32} (ungef.) +STR_2311 :{WINDOW_COLOUR_2}Nervenkitzelwert: {BLACK}{COMMA2DP32} (ungefähr) +STR_2312 :{WINDOW_COLOUR_2}Intensitätswert: {BLACK}{COMMA2DP32} (ungefähr) +STR_2313 :{WINDOW_COLOUR_2}Übelkeitswert: {BLACK}{COMMA2DP32} (ungefähr) STR_2314 :{WINDOW_COLOUR_2}Fahrtlänge: {BLACK}{STRINGID} -STR_2315 :{WINDOW_COLOUR_2}Kosten: {BLACK}ungef. {CURRENCY} -STR_2316 :{WINDOW_COLOUR_2}Erforderl. Platz {BLACK}{COMMA16} x {COMMA16} Blöcke +STR_2315 :{WINDOW_COLOUR_2}Kosten: {BLACK}ungefähr {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Erforderlicher Platz: {BLACK}{COMMA16} x {COMMA16} Blöcke STR_2317 :{WINDOW_COLOUR_2}Soundqualität: STR_2318 :Niedrig STR_2319 :Mittel STR_2320 :Hoch -STR_2321 :{WINDOW_COLOUR_2}Anzahl der Bahnen/Attraktionen: {BLACK}{COMMA16} +STR_2321 :{WINDOW_COLOUR_2}Anzahl der Attraktionen: {BLACK}{COMMA16} STR_2322 :{WINDOW_COLOUR_2}Personal: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Parkgröße: {BLACK}{COMMA32}m{SQUARED} STR_2324 :{WINDOW_COLOUR_2}Parkgröße: {BLACK}{COMMA32}Quadratfuß @@ -2330,7 +2330,7 @@ STR_2325 :{SMALLFONT}{BLACK}Land für Parkvergrößerung kaufen STR_2326 :{SMALLFONT}{BLACK}Kaufen Sie Baurechte für Bauten über oder unter dem Gelände außerhalb des Parks STR_2327 :Optionen STR_2328 :{WINDOW_COLOUR_2}Währung: -STR_2329 :{WINDOW_COLOUR_2}Distanz u. Geschwind.: +STR_2329 :{WINDOW_COLOUR_2}Distanz und Geschwind.: STR_2330 :{WINDOW_COLOUR_2}Temperatur: STR_2331 :{WINDOW_COLOUR_2}Höhenmarkierungen: STR_2332 :Einheiten @@ -2342,7 +2342,7 @@ STR_2337 :Deutsche Mark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseten (Pts) STR_2340 :Lire (L) -STR_2341 :Gulden (Dfl.) +STR_2341 :Gulden (fl.) STR_2342 :Kronen (kr) STR_2343 :Euro ({EURO}) STR_2344 :Englisch @@ -2354,22 +2354,22 @@ STR_2349 :{WINDOW_COLOUR_2}Lohn: {BLACK}{CURRENCY} pro Monat STR_2350 :{WINDOW_COLOUR_2}Angestellt: {BLACK}{MONTHYEAR} STR_2351 :{WINDOW_COLOUR_2}Gemähte Rasen: {BLACK}{COMMA16} STR_2352 :{WINDOW_COLOUR_2}Bewässerte Beete: {BLACK}{COMMA16} -STR_2353 :{WINDOW_COLOUR_2}Beseit. Abfall: {BLACK}{COMMA16} -STR_2354 :{WINDOW_COLOUR_2}Gel. Mülleimer: {BLACK}{COMMA16} -STR_2355 :{WINDOW_COLOUR_2}Repar. Bahnen: {BLACK}{COMMA16} -STR_2356 :{WINDOW_COLOUR_2}Inspiz. Bahnen: {BLACK}{COMMA16} +STR_2353 :{WINDOW_COLOUR_2}Beseitigter Abfall: {BLACK}{COMMA16} +STR_2354 :{WINDOW_COLOUR_2}Geleerte Mülleimer: {BLACK}{COMMA16} +STR_2355 :{WINDOW_COLOUR_2}Reparierte Bahnen: {BLACK}{COMMA16} +STR_2356 :{WINDOW_COLOUR_2}Inspizierte Bahnen: {BLACK}{COMMA16} STR_2357 :Haus STR_2358 :Einheiten STR_2359 :Echte Werte STR_2360 :{WINDOW_COLOUR_2}Bildschirmauflösung: STR_2361 :Landschaftsglättung STR_2362 :{SMALLFONT}{BLACK}Kantenglättung des Landschaftsquadrats ein-/ausschalten -STR_2363 :Gitterlinien bei Landschaft +STR_2363 :Gitterlinien auf Landschaft STR_2364 :{SMALLFONT}{BLACK}Gitterlinien bei Landschaft ein-/ausblenden STR_2365 :Die Bank will Ihr Darlehen nicht erhöhen! STR_2366 :Celsius ({DEGREE}C) STR_2367 :Fahrenheit (F) -STR_2368 :Kein +STR_2368 :Keine STR_2369 :Niedrig STR_2370 :Durchschnitt STR_2371 :Hoch @@ -2391,7 +2391,7 @@ STR_2386 :{BLACK}Mindestens {COMMA16} Parkbesucher bis {MONTHYEAR} und eine P STR_2387 :{BLACK}Einen Verkehrswert von mindestens {POP16}{POP16}{CURRENCY} zu erreichen bis {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR} STR_2388 :{BLACK}Viel Spaß! STR_2389 :{BLACK}Bauen Sie Ihre(n) beste(n) {STRINGID}! -STR_2390 :{BLACK}Mindestens 10 verschiedene Achterbahntypen in Ihrem Park zu betreiben, wobei jeder einen Nervenkitzelwert von mindestens 6.00 aufweisen muss +STR_2390 :{BLACK}Mindestens 10 verschiedene Achterbahntypen in Ihrem Park zu betreiben, wobei jeder einen Nervenkitzelwert von mindestens 6,00 aufweisen muss STR_2391 :{BLACK}Mindestens {COMMA16} Parkbesucher zu erreichen. Die Parkbewertung darf zu keinem Zeitpunkt unter 700 fallen! STR_2392 :{BLACK}Monatliche Einkünfte durch Fahrttickets von mindestens {POP16}{POP16}{CURRENCY} zu erreichen STR_2393 :{BLACK}Mindestens 10 verschiedene Achterbahntypen in Ihrem Park zu betreiben, wobei jeder eine Mindestlänge von {LENGTH} und einen Nervenkitzelwert von mindestens 7.00 aufweisen muss @@ -2408,8 +2408,8 @@ STR_2403 :Besucherzahl im Park STR_2404 :Monatliche Einkünfte durch Fahrttickets STR_2405 :Bauen Sie 10 Achterb. einer best. Länge STR_2406 :Stellen Sie den Bau von 5 Achterb. fertig -STR_2407 :Darleh. zurückz. u. best. Verkehrsw. err. -STR_2408 :Monatl. Gewinn d. Speisen/Werbeartikel +STR_2407 :Darlehen zurückzahlen und bestimmten Verkehrswert erreichen +STR_2408 :Monatlicher Gewinn durch Speisen/Werbeartikel STR_2409 :{WINDOW_COLOUR_2}Gerade durchgeführte Marketingkampagnen STR_2410 :{BLACK}Keine STR_2411 :{WINDOW_COLOUR_2}Verfügbare Marketingkampagnen @@ -2419,21 +2419,21 @@ STR_2414 :(Nicht ausgewählt) STR_2415 :{WINDOW_COLOUR_2}Bahn: STR_2416 :{WINDOW_COLOUR_2}Artikel: STR_2417 :{WINDOW_COLOUR_2}Dauer: -STR_2418 :Freier Eintritt für {STRINGID} +STR_2418 :freien Eintritt für {STRINGID} STR_2419 :Freifahrt für {STRINGID} -STR_2420 :Halber Eintrittspreis für {STRINGID} +STR_2420 :halben Eintrittspreis für {STRINGID} STR_2421 :Gratis-{STRINGID} STR_2422 :Werbekampagne für {STRINGID} STR_2423 :Werbekampagne für {STRINGID} STR_2424 :{WINDOW_COLOUR_2}Gutscheine für freien Eintritt in den Park -STR_2425 :{WINDOW_COLOUR_2}Gutscheine für Freifahrt auf best. Bahn -STR_2426 :{WINDOW_COLOUR_2}Gutscheine für halben Eintrittspreis z. Park -STR_2427 :{WINDOW_COLOUR_2}Gutscheine für kostenl. Speise oder Getränk +STR_2425 :{WINDOW_COLOUR_2}Gutscheine für Freifahrt auf bestimmter Bahn +STR_2426 :{WINDOW_COLOUR_2}Gutscheine für halben Eintrittspreis in den Park +STR_2427 :{WINDOW_COLOUR_2}Gutscheine für kostenlose Speise oder Getränk STR_2428 :{WINDOW_COLOUR_2}Werbekampagne für den Park STR_2429 :{WINDOW_COLOUR_2}Werbekampagne für eine bestimmte Bahn -STR_2430 :{BLACK}Gutscheine f. freien Eintr. z.{STRINGID} -STR_2431 :{BLACK}Gutscheine f. Freifahrt auf {STRINGID} -STR_2432 :{BLACK}Gutscheine f. halben Eintr. z. {STRINGID} +STR_2430 :{BLACK}Gutscheine für freien Eintritt z.{STRINGID} +STR_2431 :{BLACK}Gutscheine für Freifahrt auf {STRINGID} +STR_2432 :{BLACK}Gutscheine für halben Eintrittspreis z. {STRINGID} STR_2433 :{BLACK}Gutscheine für Gratis-{STRINGID} STR_2434 :{BLACK}Werbekampagne für {STRINGID} STR_2435 :{BLACK}Werbekampagne für {STRINGID} @@ -2478,22 +2478,23 @@ STR_2473 :{SMALLFONT}{BLACK}Nach neuen aufregenden Fahrten forschen STR_2474 :{SMALLFONT}{BLACK}Nach neuen Wasserbahnen forschen STR_2475 :{SMALLFONT}{BLACK}Nach neuen Läden und Ständen forschen STR_2476 :{SMALLFONT}{BLACK}Nach neuen Szenerien und Themen forschen -STR_2477 :{SMALLFONT}{BLACK}Betriebsmodus für diese Bahn/Attraktion auswählen +STR_2477 :{SMALLFONT}{BLACK}Betriebsmodus für diese Attraktion auswählen STR_2478 :{SMALLFONT}{BLACK}Geschwindigkeitsdiagramm im Zeitverlauf anzeigen STR_2479 :{SMALLFONT}{BLACK}Höhendiagramm im Zeitverlauf anzeigen STR_2480 :{SMALLFONT}{BLACK}Diagramm der vertikalen Beschleunigung im Zeitverlauf anzeigen STR_2481 :{SMALLFONT}{BLACK}Diagramm der seitlichen Beschleunigung im Zeitverlauf anzeigen -STR_2482 :{SMALLFONT}{BLACK}Gewinn: {CURRENCY} pro Woche, Verkehrswert: {CURRENCY} +STR_2482 :{SMALLFONT}{BLACK}Gewinn: {CURRENCY} pro Woche{NEWLINE}Verkehrswert: {CURRENCY} STR_2483 :{WINDOW_COLOUR_2}Wöchentlicher Gewinn: {BLACK}+{CURRENCY2DP} STR_2484 :{WINDOW_COLOUR_2}Wöchentlicher Gewinn: {RED}{CURRENCY2DP} STR_2485 :Steuerung STR_2486 :Allgemein -STR_2487 :Echte Besuchernamen anzeigen +STR_2487 :`Echte' Besuchernamen anzeigen STR_2488 :{SMALLFONT}{BLACK}Zwischen `echten' Besuchernamen und Besucherzahlen umschalten -STR_2489 :Kürzeltasten... -STR_2490 :Tastaturkürzel -STR_2491 :Tast. zur. -STR_2492 :{SMALLFONT}{BLACK}Alle Kürzeltasten auf Standardeinstellung zurücksetzen +STR_2489 :Tastenkürzel... +STR_2490 :Tastenkürzel +#new +STR_2491 :Tasten zurücksetzen +STR_2492 :{SMALLFONT}{BLACK}Alle Tastenkürzel auf Standardeinstellung zurücksetzen STR_2493 :Oberstes Fenster schließen STR_2494 :Alle freien Fenster schließen STR_2495 :Baumodus abbrechen @@ -2682,37 +2683,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :Alle Forschungen beendet +STR_2681 :{MEDIUMFONT}{BLACK}Erhöht Ihr Geld um 5.000 +STR_2682 :{MEDIUMFONT}{BLACK}Zw. freiem und kostenpfl. Eintritt umsch. +STR_2683 :{MEDIUMFONT}{BLACK}Erhöht das Vergnügen der Besucher maximal +STR_2684 :{MEDIUMFONT}{BLACK}Eine große Gruppe von Besuchern tritt ein +STR_2685 :`Simplex Noise' Param. +STR_2686 :{WINDOW_COLOUR_2}Niedrig: +STR_2687 :{WINDOW_COLOUR_2}Hoch: +STR_2688 :{WINDOW_COLOUR_2}Basisfrequenz: +STR_2689 :{WINDOW_COLOUR_2}Oktaven: +STR_2690 :Kartengenerierung +STR_2691 :{WINDOW_COLOUR_2}Basishöhe: +STR_2692 :{WINDOW_COLOUR_2}Wasserhöhe: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generieren +STR_2695 :Zufälliges Terrain +STR_2696 :Bäume platzieren STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave-Frequenz: +STR_2701 :Jede Woche +STR_2702 :Alle 2 Wochen +STR_2703 :Jeden Monat +STR_2704 :Alle 4 Monate +STR_2705 :Jedes Jahr +STR_2706 :Nie +STR_2707 :Neues Fenster +STR_2708 :{WINDOW_COLOUR_1}Sind Sie sicher, dass Sie {STRINGID} überschreiben möchten? +STR_2709 :Überschreiben +STR_2710 :Geben Sie den Dateinamen ein: STR_2711 :; STR_2712 := STR_2713 :, @@ -2720,56 +2721,56 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(Hoch) +STR_2719 :(Neue Datei) +STR_2720 :{UINT16}Sek. +STR_2721 :{UINT16}Sek. +STR_2722 :{UINT16}Min:{UINT16}Sek. +STR_2723 :{UINT16}Min:{UINT16}Sek. +STR_2724 :{UINT16}Min:{UINT16}Sek. +STR_2725 :{UINT16}Min:{UINT16}Sek. +STR_2726 :{UINT16}Min. +STR_2727 :{UINT16}Min. +STR_2728 :{UINT16}Stunde:{UINT16}Min. +STR_2729 :{UINT16}Stunde:{UINT16}Min. +STR_2730 :{UINT16}Stunden:{UINT16}Min. +STR_2731 :{UINT16}Stunden:{UINT16}Min. +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Jahr {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Jahr {COMMA16} +STR_2738 :Musik im Hauptmenü: +STR_2739 :Keine +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat nicht gefunden +STR_2743 :Kopieren Sie data\css17.dat aus Ihrem RCT1-Verzeichnis nach data\css50.dat in Ihrem RCT2-Verzeichnis. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Leiste -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? -STR_2757 :??? -STR_2758 :??? -STR_2759 :??? +STR_2749 :Mein neues Szenario # New strings used in the cheats window previously these were ??? -STR_2760 :+5000 Geld +STR_2750 :Alle Gegenstände nach oben bewegen +STR_2751 :Alle Gegenstände nach unten bewegen +STR_2752 :Gras beseitigen +STR_2753 :Rasen mähen +STR_2754 :Pflanzen gießen +STR_2755 :Vandalismus bes. +STR_2756 :Müll beseitigen +STR_2757 :Schönes Wetter +STR_2758 :Gewitter +STR_2759 :Höhen auf Null +STR_2760 :+5.000 Geld STR_2761 :Bezahlen für Eintritt STR_2762 :Bezahlen für Bahnen STR_2763 :??? STR_2764 :Glückliche Gäste -STR_2765 :Große Menschenmenge -STR_2766 :??? +STR_2765 :Große Straßenbahn +STR_2766 :Szenario gewinnen STR_2767 :Wetter stoppen STR_2768 :Wetter fortsetzen STR_2769 :Park öffnen @@ -2779,64 +2780,64 @@ STR_2772 :Zeit schneller STR_2773 :Fenstermodus STR_2774 :Vollbild STR_2775 :Vollbild (Desktop) -STR_2776 :Sprache +STR_2776 :Sprache: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +STR_2779 :Ansichtsfenster {COMMA16} +STR_2780 :Extra Ansichtsfenster # End of new strings -STR_2779 :??? -STR_2780 :??? STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :UMSCHALT + STR_2783 :STRG + STR_2784 :Tastaturkürzel ändern -STR_2785 :{WINDOW_COLOUR_2}Drücken Sie die neue Kürzeltaste für:-{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2785 :{WINDOW_COLOUR_2}Drücken Sie die neue Taste für:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} STR_2786 :{SMALLFONT}{BLACK}Klicken Sie auf die Kürzelbeschreibung, um eine neue Taste auszuwählen STR_2787 :{WINDOW_COLOUR_2}Verkehrswert: {BLACK}{CURRENCY} STR_2788 :{WINDOW_COLOUR_2}Glückwunsch!{NEWLINE}{BLACK}Sie haben Ihr Ziel mit einem Firmenwert von {CURRENCY} erreicht! STR_2789 :{WINDOW_COLOUR_2}Sie haben Ihr Ziel nicht erreicht! STR_2790 :Geben Sie einen Namen in das Szenariodiagramm ein STR_2791 :Namen eingeben -STR_2792 :Geben Sie Ihren Namen für das Szenariodiagramm ein:- +STR_2792 :Geben Sie Ihren Namen für das Szenariodiagramm ein: STR_2793 :{SMALLFONT}(Durchgeführt von {STRINGID}) STR_2794 :{WINDOW_COLOUR_2}Durchgeführt von: {BLACK}{STRINGID}{NEWLINE}{WINDOW_COLOUR_2} mit einem Firmenwert von: {BLACK}{CURRENCY} STR_2795 :Sortieren STR_2796 :{SMALLFONT}{BLACK}Sortieren Sie die Bahnliste in die richtige Reihenfolge mit Hilfe der angezeigten Informationsart STR_2797 :Ansicht rollen, wenn Zeiger am Bildschirmrand ist STR_2798 :{SMALLFONT}{BLACK}Wählen Sie aus, ob die Ansicht gerollt werden soll, wenn sich der Mauszeiger am Bildschirmrand befindet -STR_2799 :{SMALLFONT}{BLACK}Steuertastenzuweisungen anzeigen oder ändern +STR_2799 :{SMALLFONT}{BLACK}Tastenkürzel anzeigen oder ändern STR_2800 :{WINDOW_COLOUR_2}Besucher gesammt: {BLACK}{COMMA32} -STR_2801 :{WINDOW_COLOUR_2}Einkünfte durch Eintrittskarten: {BLACK}{CURRENCY2DP} +STR_2801 :{WINDOW_COLOUR_2}Einkünfte d. Eintrittskarten: {BLACK}{CURRENCY2DP} STR_2802 :Karte STR_2803 :{SMALLFONT}{BLACK}Diese Besucher auf Karte hervorheben STR_2804 :{SMALLFONT}{BLACK}Diese Mitarbeiter auf Karte hervorheben STR_2805 :{SMALLFONT}{BLACK}Parkkarte anzeigen -STR_2806 :{RED}Die Besucher beschweren sich über den schrecklichen Zustand der Fußwege in Ihrem Park{NEWLINE}Überprüfen Sie, wo Ihre Handwerker sind, und organisieren Sie sie erforderlichenfalls besser -STR_2807 :{RED}Die Besucher beschweren sich über das Müllaufkommen in Ihrem Park{NEWLINE}Überprüfen Sie, wo Ihre Handwerker sind, und organisieren Sie sie erforderlichenfalls besser +STR_2806 :{RED}Die Besucher beschweren sich über den schrecklichen Zustand der Fußwege in Ihrem Park{NEWLINE}Überprüfen Sie, wo Ihre Parkpfleger sind, und organisieren Sie sie erforderlichenfalls besser +STR_2807 :{RED}Die Besucher beschweren sich über das Müllaufkommen in Ihrem Park{NEWLINE}Überprüfen Sie, wo Ihre Parkpfleger sind, und organisieren Sie sie erforderlichenfalls besser STR_2808 :{RED}Die Besucher beschweren sich über den Vandalismus in Ihrem Park{NEWLINE}Überprüfen Sie, wo Ihre Aufseher sind, und organisieren Sie sie erforderlichenfalls besser STR_2809 :{RED}Die Besucher sind hungrig und können nirgendwo etwas finden, um Speisen zu kaufen STR_2810 :{RED}Die Besucher sind durstig und können nirgendwo etwas finden, um Getränke zu kaufen STR_2811 :{RED}Die Besucher beschweren sich, weil sie die Toiletten in Ihrem Park nicht finden können STR_2812 :{RED}Die Besucher verirren sich oder es kommt zu Staus{NEWLINE}Überprüfen Sie, ob die Anordnung Ihrer Fußwege eventuell verbessert werden muss, damit die Besucher sich zurechtfinden STR_2813 :{RED}Der Eintrittspreis für Ihren Park ist zu hoch!{NEWLINE}Verringern Sie den Eintrittspreis oder verbessern Sie das Parkangebot, um mehr Besucher anzuziehen -STR_2814 :{WINDOW_COLOUR_2}Auszeichnug f. ungepflegtesten Park -STR_2815 :{WINDOW_COLOUR_2}Auszeichnung f. saubersten Park -STR_2816 :{WINDOW_COLOUR_2}Auszeichnung f. Park mit besten Achterbahnen -STR_2817 :{WINDOW_COLOUR_2}Auszeichnung f. Park mit bestem Angebot -STR_2818 :{WINDOW_COLOUR_2}Auszeichnung f. den schönsten Park -STR_2819 :{WINDOW_COLOUR_2}Auszeichnung f. Park m. schlimmst. Ang. -STR_2820 :{WINDOW_COLOUR_2}Auszeichnung f. den sichersten Park -STR_2821 :{WINDOW_COLOUR_2}Auszeichnung f. das beste Personal -STR_2822 :{WINDOW_COLOUR_2}Auszeichnung f. bestes Essen -STR_2823 :{WINDOW_COLOUR_2}Auszeichnung f. schlechtestes Essen -STR_2824 :{WINDOW_COLOUR_2}Auszeichnung f. beste Parktoiletten -STR_2825 :{WINDOW_COLOUR_2}Auszeichnung f. enttäuschendsten Park -STR_2826 :{WINDOW_COLOUR_2}Auszeichnung f. die besten Wasserbahnen -STR_2827 :{WINDOW_COLOUR_2}Auszeichnung f. beste selbstentw. Bahn. -STR_2828 :{WINDOW_COLOUR_2}Auszeichnung f. bunteste Farbschemas -STR_2829 :{WINDOW_COLOUR_2}Auszeichnung f. konfuseste Parkanordn. -STR_2830 :{WINDOW_COLOUR_2}Auszeichnung f. beste gemäßigte Bahn +STR_2814 :{WINDOW_COLOUR_2}Auszeichnung für ungepflegtesten Park +STR_2815 :{WINDOW_COLOUR_2}Auszeichnung für saubersten Park +STR_2816 :{WINDOW_COLOUR_2}Auszeichnung für Park mit den besten Achterbahnen +STR_2817 :{WINDOW_COLOUR_2}Auszeichnung für Park mit bestem Angebot +STR_2818 :{WINDOW_COLOUR_2}Auszeichnung für den schönsten Park +STR_2819 :{WINDOW_COLOUR_2}Auszeichnung für Park mit schlimmstem Angebot +STR_2820 :{WINDOW_COLOUR_2}Auszeichnung für den sichersten Park +STR_2821 :{WINDOW_COLOUR_2}Auszeichnung für das beste Personal +STR_2822 :{WINDOW_COLOUR_2}Auszeichnung für bestes Essen +STR_2823 :{WINDOW_COLOUR_2}Auszeichnung für schlechtestes Essen +STR_2824 :{WINDOW_COLOUR_2}Auszeichnung für beste Parktoiletten +STR_2825 :{WINDOW_COLOUR_2}Auszeichnung für enttäuschendsten Park +STR_2826 :{WINDOW_COLOUR_2}Auszeichnung für die besten Wasserbahnen +STR_2827 :{WINDOW_COLOUR_2}Auszeichnung für beste selbstentwickelte Bahn +STR_2828 :{WINDOW_COLOUR_2}Auszeichnung für bunteste Farbschemas +STR_2829 :{WINDOW_COLOUR_2}Auszeichnung für konfuseste Parkanordnung +STR_2830 :{WINDOW_COLOUR_2}Auszeichnung für beste gemäßigte Bahn STR_2831 :{TOPAZ}Ihr Park hat die Auszeichnung `Ungepflegtester Park des Landes' erhalten! -STR_2832 :{TOPAZ}Ihr Park hat die Auszeichnung `Säuberster Park des Landes' erhalten! +STR_2832 :{TOPAZ}Ihr Park hat die Auszeichnung `Sauberster Park des Landes' erhalten! STR_2833 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit den besten Achterbahnen' erhalten! STR_2834 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit dem besten Angebot des Landes' erhalten! STR_2835 :{TOPAZ}Ihr Park hat die Auszeichnung `Schönster Park des Landes' erhalten! @@ -2858,7 +2859,7 @@ STR_2850 :Neuer Streckenentwurf erfolgreich installiert STR_2851 :Szenario bereits installiert STR_2852 :Streckenentwurf bereits installiert STR_2853 :Von der örtlichen Behörde verboten! -STR_2854 :{RED}Besucher gelangen nicht zum Eingang von {STRINGID} !{NEWLINE}Bauen Sie einen Fußweg zum Eingang +STR_2854 :{RED}Besucher gelangen nicht zum Eingang von {STRINGID}!{NEWLINE}Bauen Sie einen Fußweg zum Eingang STR_2855 :{RED}{STRINGID} hat keinen Fußweg, der vom Ausgang wegführt!{NEWLINE}Legen Sie einen Fußweg an, der vom Bahnausgang wegführt STR_2856 :{WINDOW_COLOUR_2}Lehrgang STR_2857 :{WINDOW_COLOUR_2}(Drücken Sie eine Taste oder klicken Sie mit der Maus, um die Kontrolle zu übernehmen) @@ -2982,12 +2983,12 @@ STR_2974 :Alternatives Farbschema 3 STR_2975 :{SMALLFONT}{BLACK}Wählen Sie das Farbschema aus, das geändert oder mit dem eine Bahn gestrichen werden soll STR_2976 :{SMALLFONT}{BLACK}Streichen Sie einen bestimmten Bereich dieser Bahn mit dem ausgewählten Farbschema STR_2977 :Mitarbeitername -STR_2978 :Neuen Namen für diesen Mitarbeiter eingeben:- +STR_2978 :Neuen Namen für diesen Mitarbeiter eingeben: STR_2979 :Dieser Mitarbeiter kann nicht benannt werden... STR_2980 :Zu viele Banner im Spiel STR_2981 :{RED}Kein Zutritt - - STR_2982 :Bannertext -STR_2983 :Neuen Text für diesen Banner eingeben:- +STR_2983 :Neuen Text für diesen Banner eingeben: STR_2984 :Neuer Text für den Banner kann nicht erstellt werden... STR_2985 :Banner STR_2986 :{SMALLFONT}{BLACK}Text auf Banner ändern @@ -2997,7 +2998,7 @@ STR_2989 :{SMALLFONT}{BLACK}Hauptfarbe auswählen STR_2990 :{SMALLFONT}{BLACK}Textfarbe auswählen STR_2991 :Schild STR_2992 :Schildtext -STR_2993 :Neuen Text für dieses Schild eingeben:- +STR_2993 :Neuen Text für dieses Schild eingeben: STR_2994 :{SMALLFONT}{BLACK}Text auf Schild ändern STR_2995 :{SMALLFONT}{BLACK}Dieses Schild abreißen STR_2996 :{BLACK}ABC @@ -3075,7 +3076,7 @@ STR_3067 :{OPENQUOTES}Echte{ENDQUOTES} Parks STR_3068 :Andere Parks STR_3069 :Oberster Abschnitt STR_3070 :Neigung auf Ebene -STR_3071 :{WINDOW_COLOUR_2}Gleicher Preis überall +STR_3071 :{WINDOW_COLOUR_2}Gleicher Preis im ganzen Park STR_3072 :{SMALLFONT}{BLACK}Bestimmen Sie, ob dieser Preis im gesamten Park gilt STR_3073 :{RED}WARNUNG: Ihre Parkbewertung ist unter den Wert 700 gefallen!{NEWLINE}Wenn Sie die Parkbewertung innerhalb 4 Wochen nicht erhöhen, wird der Park geschlossen STR_3074 :{RED}WARNUNG: Ihre Parkbewertung liegt immer noch unter dem Wert 700!{NEWLINE}Sie haben noch 3 Wochen Zeit, um die Parkbewertung zu erhöhen @@ -3089,7 +3090,7 @@ STR_3081 :Burgeingang (grau) STR_3082 :Burgeingang (braun) STR_3083 :Dschungeleingang STR_3084 :Blockhütteneingang -STR_3085 :Klassischer/Röm. Eingang +STR_3085 :Klassischer/Römischer Eingang STR_3086 :Abstrakter Eingang STR_3087 :Schnee-/Eis-Eingang STR_3088 :Pagodeneingang @@ -3099,7 +3100,7 @@ STR_3091 :Sie dürfen diesen Abschnitt nicht entfernen! STR_3092 :Sie dürfen die Station für diese Bahn nicht verschieben oder verändern! STR_3093 :{WINDOW_COLOUR_2}Favorit: {BLACK}{STRINGID} STR_3094 :N/A -STR_3095 :{WINDOW_COLOUR_2}Lifthüg.-Kettengeschw.: +STR_3095 :{WINDOW_COLOUR_2}Lifthügel-Kettengeschw.: STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} STR_3097 :{SMALLFONT}{BLACK}Lifthügel-Kettengeschwindigkeit auswählen STR_3098 :Lifthügelgeschwindigkeit kann nicht geändert werden... @@ -3113,7 +3114,7 @@ STR_3105 :{SMALLFONT}{BLACK}Läden und Stände auflisten STR_3106 :{SMALLFONT}{BLACK}Informationskiosks und andere Besuchereinrichtungen auflisten STR_3107 :Schließen STR_3108 :Testen -STR_3109 :Eröffnen +STR_3109 :Öffnen STR_3110 :{WINDOW_COLOUR_2}Blockbereiche: {BLACK}{COMMA16} STR_3111 :{SMALLFONT}{BLACK}Klicken Sie auf den Entwurf, um ihn zu bauen STR_3112 :{SMALLFONT}{BLACK}Klicken Sie auf den Entwurf, um ihn umzubenennen oder zu löschen @@ -3128,7 +3129,7 @@ STR_3120 :{SMALLFONT}{BLACK}Nächsten verfügbaren Mechaniker oder Mechaniker STR_3121 :Örtlicher Mechaniker kann nicht gefunden werden, oder alle Mechaniker sind gerade beschäftigt STR_3122 :{WINDOW_COLOUR_2}Lieblingsbahn von: {BLACK}{COMMA16} Besucher STR_3123 :{WINDOW_COLOUR_2}Lieblingsbahn von: {BLACK}{COMMA16} Besuchern -STR_3124 :Kaputt {STRINGID} +STR_3124 :Defekt {STRINGID} STR_3125 :{WINDOW_COLOUR_2}Nervenkitzelfaktor: {BLACK}+{COMMA16}% STR_3126 :{WINDOW_COLOUR_2}Intensitätsfaktor: {BLACK}+{COMMA16}% STR_3127 :{WINDOW_COLOUR_2}Übelkeitsfaktor: {BLACK}+{COMMA16}% @@ -3141,7 +3142,7 @@ STR_3133 :Dies kann nicht auf schrägem Untergrund gebaut werden STR_3134 :{RED}(Der Entwurf enthält Szenerie, die nicht verfügbar ist) STR_3135 :{RED}(Fahrzeugentwurf nicht verfügbar - Dies kann sich auf die Bahn-Performance auswirken) STR_3136 :Warnung: Dieser Entwurf wird mit einer alternativen Fahrzeugart gebaut und könnte möglicherweise nicht wie gewünscht funktionieren -STR_3137 :Nahe Szenerie ausw. +STR_3137 :Nahe Szenerie auswählen STR_3138 :Auswahl zurücksetzen STR_3139 :Kabellift funktioniert nicht in diesem Betriebsmodus STR_3140 :Kabellifthügel muss direkt nach der Station beginnen @@ -3183,12 +3184,12 @@ STR_3175 :Dieses Objekt wird immer benötigt STR_3176 :Dieses Objekt kann nicht ausgewählt werden STR_3177 :Die Auswahl dieses Objekts kann nicht aufgehoben werden STR_3178 :Es muss mindestens ein Fußwegobjekt ausgewählt werden -STR_3179 :Es muss mindestens ein Bahnfahrzeug/Attraktionsobjekt ausgewählt werden +STR_3179 :Es muss mindestens ein Attraktionsobjekt ausgewählt werden STR_3180 :Ungültige Auswahl an Objekten STR_3181 :Objektauswahl - {STRINGID} STR_3182 :Parkeingangsart muss ausgewählt werden STR_3183 :Wasserart muss ausgewählt werden -STR_3184 :Bahnfahrzeuge/Attraktionen +STR_3184 :Attraktionen STR_3185 :Kleine Szenerie STR_3186 :Große Szenerie STR_3187 :Wände/Zäune @@ -3260,14 +3261,14 @@ STR_3252 :Max. Darlehensgröße kann nicht weiter erhöht werden! STR_3253 :Max. Darlehensgröße kann nicht weiter reduziert werden! STR_3254 :Zinsrate kann nicht weiter erhöht werden! STR_3255 :Zinsrate kann nicht weiter reduziert werden! -STR_3256 :Weniger aufreg. Bahnen bevorzugt +STR_3256 :Weniger aufregendere Bahnen bevorzugt STR_3257 :{SMALLFONT}{BLACK}Wählen Sie aus, ob die Besucher im Allgemeinen weniger aufregende Bahnen vorziehen STR_3258 :Aufregendere Bahnen bevorzugt STR_3259 :{SMALLFONT}{BLACK}Wählen Sie aus, ob die Besucher im Allgemeinen aufregendere Bahnen vorziehen -STR_3260 :{WINDOW_COLOUR_2}Durchschn. Geld pro Bes.: -STR_3261 :{WINDOW_COLOUR_2}Anfangsvergn. d. Besuch.: -STR_3262 :{WINDOW_COLOUR_2}Anfangshunger d. Besuch.: -STR_3263 :{WINDOW_COLOUR_2}Anfangsdurst d. Besucher: +STR_3260 :{WINDOW_COLOUR_2}Durchschnittliches Geld pro Besucher: +STR_3261 :{WINDOW_COLOUR_2}Anfangsvergnügen der Besucher: +STR_3262 :{WINDOW_COLOUR_2}Anfangshunger der Besucher: +STR_3263 :{WINDOW_COLOUR_2}Anfangsdurst der Besucher: STR_3264 :Dies kann nicht weiter erhöht werden! STR_3265 :Dies kann nicht weiter reduziert werden! STR_3266 :{SMALLFONT}{BLACK}Wählen Sie aus, was der Park für Eintritt und Fahrten verlangt @@ -3283,8 +3284,8 @@ STR_3275 :Höhere Schwierigkeitsstufe für Besuchergewinnung STR_3276 :{SMALLFONT}{BLACK}Machen Sie das Anlocken von Besuchern schwieriger STR_3277 :{WINDOW_COLOUR_2}Kosten für Landkauf: STR_3278 :{WINDOW_COLOUR_2}Kosten für Erwerb v. Baurechten: -STR_3279 :Freier Eintritt/Bez. pro Fahrt -STR_3280 :Bez. f. Eintritt/Gratis fahren +STR_3279 :Freier Eintritt/Bezahlen pro Fahrt +STR_3280 :Bezahlen für Eintritt/Gratis fahren STR_3281 :{WINDOW_COLOUR_2}Eintrittspreis: STR_3282 :{SMALLFONT}{BLACK}Ziel und Parkname auswählen STR_3283 :{SMALLFONT}{BLACK}Bahnen auswählen, die beibehalten werden sollen @@ -3298,7 +3299,7 @@ STR_3290 :Kühl und feucht STR_3291 :Warm STR_3292 :Heiß und trocken STR_3293 :Kalt -STR_3294 :Änderung... +STR_3294 :Ändern... STR_3295 :{SMALLFONT}{BLACK}Namen des Parks ändern STR_3296 :{SMALLFONT}{BLACK}Namen des Szenarios ändern STR_3297 :{SMALLFONT}{BLACK}Detailhinweise zu Park/Szenario ändern @@ -3308,19 +3309,19 @@ STR_3300 :{WINDOW_COLOUR_2}Szenarioname: {BLACK}{STRINGID} STR_3301 :{WINDOW_COLOUR_2}Zieldatum: STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} STR_3303 :{WINDOW_COLOUR_2}Besucheranzahl: -STR_3304 :{WINDOW_COLOUR_2}Verkehrsw.: +STR_3304 :{WINDOW_COLOUR_2}Verkehrswert: STR_3305 :{WINDOW_COLOUR_2}Mon. Einkünfte: -STR_3306 :{WINDOW_COLOUR_2}Mon. Gewinn: +STR_3306 :{WINDOW_COLOUR_2}Monatlicher Gewinn: STR_3307 :{WINDOW_COLOUR_2}Mindestlänge: STR_3308 :{WINDOW_COLOUR_2}Nervenkitzelwert: STR_3309 :{WINDOW_COLOUR_2}{COMMA16} STR_3310 :{WINDOW_COLOUR_2}{LENGTH} STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} -STR_3312 :{WINDOW_COLOUR_2}Bahnen/Attrakt. unter Beibehaltungsauftrag: +STR_3312 :{WINDOW_COLOUR_2}Attraktionen unter Beibehaltungsauftrag: STR_3313 :Szenarioname -STR_3314 :Namen für Szenario eingeben:- +STR_3314 :Namen für Szenario eingeben: STR_3315 :Park-/Szenariodetails -STR_3316 :Beschreibung für dieses Szenario eingeben:- +STR_3316 :Beschreibung für dieses Szenario eingeben: STR_3317 :Noch keine Details STR_3318 :{SMALLFONT}{BLACK}Wählen Sie aus, in welcher Gruppe dieses Szenario vorkommt STR_3319 :{WINDOW_COLOUR_2}Szenariogruppe: @@ -3355,7 +3356,7 @@ STR_3347 :Bahn ist zu lang, enthält zu viele Elemente oder Szenerie ist zu z STR_3348 :Umbenennen STR_3349 :Löschen STR_3350 :Streckenentwurfsname -STR_3351 :Neuen Namen für diesen Streckenentwurf eingeben:- +STR_3351 :Neuen Namen für diesen Streckenentwurf eingeben: STR_3352 :Streckenentwurf kann nicht umbenannt werden... STR_3353 :Neuer Name enthält ungültige Zeichen STR_3354 :Entweder besteht bereits eine Datei mit diesem Namen oder die Datei ist schreibgeschützt @@ -3368,7 +3369,7 @@ STR_3360 :Warnung! STR_3361 :Zu viele Streckenentwürfe dieser Art - einige werden nicht aufgeführt. STR_3362 :Erzwungenes Software-Buffer-Mixing STR_3363 :{SMALLFONT}{BLACK}Diese Option wählen, falls das Spiel jedesmal kurz anhält sobald Töne gespielt werden oder falls ein Rauschen zu hören ist. -STR_3364 :Fortgeschr. +STR_3364 :Fortgeschritten STR_3365 :{SMALLFONT}{BLACK}Ermöglichen Sie die Auswahl einzelner Szenerieobjekte zusätzlich zu Szeneriegruppen STR_3366 :{BLACK}= Bahn STR_3367 :{BLACK}= Imbissstand @@ -3406,7 +3407,7 @@ STR_3398 :{SMALLFONT}{BLACK}Eine Bahn braucht einen Eingang und einen Ausgang STR_3399 :{SMALLFONT}{BLACK}Es müssen Fußwege gebaut werden, auf denen die Besucher zu unserer neuen Bahn gehen können... STR_3400 :{SMALLFONT}{BLACK}Für den Weg zum Bahneingang verwenden wir einen speziellen `Warteschlangen'-Weg... STR_3401 :{SMALLFONT}{BLACK}Für den Weg vom Ausgang genügt ein `gewöhnlicher' Fußweg... -STR_3402 :{SMALLFONT}{BLACK}OK, jetzt wird die Bahn eröffnet! Hierzu klickt man auf das Fahnensymbol im Bahnfenster und wählt `Eröffnen'... +STR_3402 :{SMALLFONT}{BLACK}OK, jetzt wird die Bahn eröffnet! Hierzu klickt man auf das Fahnensymbol im Bahnfenster und wählt `Öffnen'... STR_3403 :{SMALLFONT}{BLACK}Aber wo sind denn die Besucher? STR_3404 :{SMALLFONT}{BLACK}Ah - der Park ist ja noch geschlossen! OK, dann eröffnen wir ihn mal... STR_3405 :{SMALLFONT}{BLACK}Während wir auf die ersten Besucher warten, bauen wir etwas Szenerie... @@ -3451,3 +3452,228 @@ STR_3443 :Seite 4 STR_3444 :Seite 5 STR_3445 :Patrouillenbereich festlegen STR_3446 :Patrouillenbereich verwerfen +# New strings, cleaner +STR_5120 :Finanzen in der Symbolleiste anzeigen +STR_5121 :Forschung in der Symbolleiste anzeigen +STR_5122 :Fahrzeuge gleicher Strecke/Bahnart anzeigen +STR_5123 :Bahnen erneuern +STR_5124 :Keine Six Flags +STR_5125 :Alles zerstörbar +STR_5126 :Zufällige Titelmusik +STR_5127 :{SMALLFONT}{BLACK}Höhenanpassung deaktivieren +STR_5128 :Auswahlgröße +STR_5129 :Auswahlgröße zwischen {COMMA16} und {COMMA16} eingeben: +STR_5130 :Kartengröße +STR_5131 :Kartengröße zwischen {COMMA16} und {COMMA16} eingeben: +STR_5132 :Bahnen reparieren +STR_5133 :{SMALLFONT}{BLACK}Kleineren Landbereich anpassen +STR_5134 :{SMALLFONT}{BLACK}Größeren Landbereich anpassen +STR_5135 :{SMALLFONT}{BLACK}Kaufe Land- und Baurechte +STR_5136 :Landrechte +STR_5137 :Erlaube Lifthügel- und Antriebsgeschw.{NEWLINE}bis zu {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Deaktiviere Bremsenfehlfunktion +STR_5141 :Deaktiviere alle Störungen +STR_5142 :Normale Geschwindigkeit +STR_5143 :Erhöhte Geschwindigkeit +STR_5144 :Hohe Geschwindigkeit +STR_5145 :Sehr Hohe Geschwindigkeit +STR_5146 :Extreme Geschwindigkeit +STR_5147 :Cheats in der Symbolleiste anzeigen +STR_5148 :{SMALLFONT}{BLACK}Spielgeschwindigkeit ändern +STR_5149 :{SMALLFONT}{BLACK}Cheats anzeigen +STR_5150 :Aktiviere Debugging-Tools +STR_5151 :. +STR_5152 :, +STR_5153 :Themen bearbeiten... +STR_5154 :Anzeige über Hardware durchführen +STR_5155 :Testen unfertiger Bahnen erlauben +STR_5156 :{SMALLFONT}{BLACK}Erlaubt das Testen der meisten Bahnarten, selbst wenn die Strecke nicht fertiggestellt ist, das gilt nicht für den Streckenmodus mit Blockbereichen +STR_5157 :Alle Preise freischalten +STR_5158 :Spiel Beenden +STR_5159 :OpenRCT2 Beenden +STR_5160 :{MONTH} {STRINGID}, Jahr {COMMA16} +STR_5161 :Datumsformat: +STR_5162 :Tag/Monat/Jahr +STR_5163 :Monat/Tag/Jahr +STR_5164 :Twitch-Kanalname +STR_5165 :Parkbesucher nach Followern benennen +STR_5166 :{SMALLFONT}{BLACK}Benennt die Parkbesucher nach den Followern des Twitch-Kanals +STR_5167 :Überwache Follower-Parkbesucher +STR_5168 :{SMALLFONT}{BLACK}Überwachungsinformationen zu Parkbesuchern, die nach Twitch-Followern benannt sind, einschalten - (Bei eingeschalteter Überwachung werden Besucheraktivitäten im Nachrichtenbereich angezeigt) +STR_5169 :Parkbesucher nach Twitch-Chatbenutzern benennen +STR_5170 :{SMALLFONT}{BLACK}Benennt die Parkbesucher nach Twitch-Chatbenutzern +STR_5171 :Überwache Chat-Parkbesucher +STR_5172 :{SMALLFONT}{BLACK}Überwachungsinformationen zu Parkbesuchern, die nach Twitch-Chatbenutzern benannt sind, einschalten - (Bei eingeschalteter Überwachung werden Besucheraktivitäten im Nachrichtenbereich angezeigt) +STR_5173 :Erhalte Twitch-Chat als Spielnachrichten +STR_5174 :{SMALLFONT}{BLACK}Benutzt Twitch-Chatnachrichten, welchen !news vorangestellt ist, für Spielbenachrichtigungen +STR_5175 :Name Ihres Twitch-Kanals eingeben: +STR_5176 :Twitch-Integration aktivieren +STR_5177 :Vollbildmodus: +STR_5178 :{SMALLFONT}{BLACK}Cheats für Finanzen anzeigen +STR_5179 :{SMALLFONT}{BLACK}Cheats für Parkbesucher anzeigen +STR_5180 :{SMALLFONT}{BLACK}Cheats für Park anzeigen +STR_5181 :{SMALLFONT}{BLACK}Cheats für Attraktionen anzeigen +STR_5182 :{INT32} +STR_5183 :Basishöhe +STR_5184 :Basishöhe zwischen {COMMA16} und {COMMA16} eingeben: +STR_5185 :Wasserhöhe +STR_5186 :Wasserhöhe zwischen {COMMA16} und {COMMA16} eingeben: +STR_5187 :Finanzen +STR_5188 :Neue Kampagne +STR_5189 :Forschung +STR_5190 :Karte +STR_5191 :Ansichtsfenster +STR_5192 :Aktuelle Nachrichten +STR_5193 :Land +STR_5194 :Wasser +STR_5195 :Szenerie entfernen +STR_5196 :Landrechte +STR_5197 :Szenerie +STR_5198 :Fußweg +STR_5199 :Bahnkonstruktion +STR_5200 :Streckenentwurf platzieren +STR_5201 :Neue Bahn +STR_5202 :Streckenentwurf auswählen +STR_5203 :Bahn +STR_5204 :Bahnliste +STR_5205 :Besucher +STR_5206 :Besucherliste +STR_5207 :Mitarbeiter +STR_5208 :Mitarbeiterliste +STR_5209 :Banner +STR_5210 :Objektauswahl +STR_5211 :Erfindungsliste +STR_5212 :Szenariooptionen +STR_5213 :Zieloptionen +STR_5214 :Kartengenerierung +STR_5215 :Streckenentwurf-Manager +STR_5216 :Streckenentwurf-Manager Liste +STR_5217 :Cheats +STR_5218 :Themen +STR_5219 :Optionen +STR_5220 :Tastenkürzel +STR_5221 :Tastenkürzel ändern +STR_5222 :Laden/Speichern +STR_5223 :Speichern +STR_5224 :Attraktion abreißen +STR_5225 :Mitarbeiter entlassen +STR_5226 :Strecke löschen +STR_5227 :Spielstand überschreiben +STR_5228 :{SMALLFONT}{BLACK}Allgemeine Benutzeroberfläche +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Werkzeuge +STR_5231 :{SMALLFONT}{BLACK}Attraktionen und Besucher +STR_5232 :{SMALLFONT}{BLACK}Editoren +STR_5233 :{SMALLFONT}{BLACK}Sonstiges +STR_5234 :{SMALLFONT}{BLACK}Eingabeaufforderungen +STR_5235 :{SMALLFONT}{BLACK}Einstellungen +STR_5236 :Fenster: +STR_5237 :Farbpalette: +STR_5238 :Aktuelles Thema: +STR_5239 :Duplizieren +STR_5240 :Name für Thema eingeben: +STR_5241 :Dieses Thema kann nicht geändert werden +STR_5242 :Dieser Themenname existiert bereits +STR_5243 :Unzulässige Zeichen benutzt +STR_5244 :Themen +STR_5245 :Obere Symbolleiste +STR_5246 :Untere Symbolleiste +STR_5247 :Untere Symbolleiste Achterb.-Designer +STR_5248 :Untere Symbolleiste Szenario-Editor +STR_5249 :Hauptmenü Schaltflächen +STR_5250 :Hauptmenü Beenden-Schaltfläche +STR_5251 :Hauptmenü Optionen-Schaltfläche +STR_5252 :Hauptmenü Szenarioauswahl +STR_5253 :Parkinformationen +STR_5254 :Übelkeit hinzufügen +STR_5255 :{MEDIUMFONT}{BLACK}Allen Besuchern wird übel +STR_5256 :Neues Thema zum bearbeiten erstellen +STR_5257 :{SMALLFONT}{BLACK}Neues Thema durch duplizieren des aktuellen Themas erstellen +STR_5258 :{SMALLFONT}{BLACK}Aktuelles Thema löschen +STR_5259 :{SMALLFONT}{BLACK}Aktuelles Thema umbenennen +STR_5260 :Riesiger Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Eigene +STR_5265 :{SMALLFONT}{BLACK}Auswählen, welche Inhaltsquellen angezeigt werden sollen +STR_5266 :{SMALLFONT}{BLACK}Anzeige +STR_5267 :{SMALLFONT}{BLACK}Sprache und Einheiten +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Steuerung +STR_5270 :{SMALLFONT}{BLACK}Sonstiges +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Kleine Szenerie +STR_5273 :{SMALLFONT}{BLACK}Große Szenerie +STR_5274 :{SMALLFONT}{BLACK}Fußwege +STR_5275 :Nach Objekten suchen +STR_5276 :Zu suchenden Objektnamen eingeben: +STR_5277 :Entfernen +STR_5278 :Sandkasten-Modus +STR_5279 :Sandk.-Modus aus +STR_5280 :{SMALLFONT}{BLACK}Erlaubt das Bearbeiten der Landrechte im Kartenfenster sowie andere Optionen welche normalerweise nur im Szenario-Editor verfügbar sind +STR_5281 :{SMALLFONT}{BLACK}Features +STR_5282 :RCT1-Ampel Bahn öffnen/schließen +STR_5283 :RCT1-Ampel Park öffnen/schließen +STR_5284 :RCT1-Schriftart Szenarioauswahl +STR_5285 :SPRENGEN!!! +STR_5286 :{MEDIUMFONT}{BLACK}Lässt Besucher explodieren +STR_5287 :Bahn ist schon defekt +STR_5288 :Bahn ist geschlossen +STR_5289 :Für diese Bahn sind keine Defekte verfügbar +STR_5290 :Bahn reparieren +STR_5291 :Kann Defekt nicht erzwingen +STR_5292 :{SMALLFONT}{BLACK}Defekt erzwingen +STR_5293 :{SMALLFONT}{BLACK}Attraktion schließen +STR_5294 :{SMALLFONT}{BLACK}Attraktion testen +STR_5295 :{SMALLFONT}{BLACK}Attraktion öffnen +STR_5296 :{SMALLFONT}{BLACK}Park schließen +STR_5297 :{SMALLFONT}{BLACK}Park öffnen +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}Personal schnell feuern +STR_5301 :{MEDIUMFONT}{BLACK}Ihr Darlehen zurückzahlen +STR_5302 :Darlehen zurückzahl. +STR_5303 :Erlaube im Pausenmodus zu bauen +STR_5304 :Titelsequenz: +STR_5305 :RollerCoaster Tycoon 1 +STR_5306 :RollerCoaster Tycoon 1 (AA) +STR_5307 :RollerCoaster Tycoon 1 (AA + LL) +STR_5308 :RollerCoaster Tycoon 2 +STR_5309 :OpenRCT2 +STR_5310 :Zufällig +STR_5311 :{SMALLFONT}{BLACK}Debugging-Tools +STR_5312 :Konsole anzeigen +STR_5313 :Kachelinspektor anzeigen +STR_5314 :Kachelinspektor +STR_5315 :Gras +STR_5316 :Sand +STR_5317 :Erde +STR_5318 :Gestein +STR_5319 :Mars +STR_5320 :Schachbrett +STR_5321 :Grasklumpen +STR_5322 :Eis +STR_5323 :Gitter (rot) +STR_5324 :Gitter (gelb) +STR_5325 :Gitter (blau) +STR_5326 :Gitter (grün) +STR_5327 :Sand (dunkel) +STR_5328 :Sand (hell) +STR_5329 :Schachbrett (invertiert) +STR_5330 :Untergrundansicht +STR_5331 :Gestein +STR_5332 :Holz (rot) +STR_5333 :Holz (schwarz) +STR_5334 :Eis +STR_5335 :Attraktionseingang +STR_5336 :Attraktionsausgang +STR_5337 :Parkeingang +STR_5338 :Elementtyp +STR_5339 :Basishöhe +STR_5340 :Lichte Höhe +STR_5341 :Kennzeichen +STR_5342 :Eine Kachel auf der Karte auswählen +STR_5343 :Personal automatisch platzieren diff --git a/data/language/hungarian.txt b/data/language/hungarian.txt index c4923aec62..90ddd747cc 100644 --- a/data/language/hungarian.txt +++ b/data/language/hungarian.txt @@ -1065,7 +1065,7 @@ STR_1060 :Invalid ride/attraction name STR_1061 :Normal mode STR_1062 :Continuous circuit mode STR_1063 :Reverse-Incline launched shuttle mode -STR_1064 :Powered launch +STR_1064 :Powered launch (passing station) STR_1065 :Shuttle mode STR_1066 :Boat hire mode STR_1067 :Upward launch @@ -1097,7 +1097,7 @@ STR_1092 :Downward launch STR_1093 :Crooked house mode STR_1094 :Freefall drop mode STR_1095 :Continuous circuit block sectioned mode -STR_1096 :Powered launch +STR_1096 :Powered launch (without passing station) STR_1097 :Powered launch block sectioned mode STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} @@ -1778,7 +1778,7 @@ STR_1773 :Only one on-ride photo section allowed per ride STR_1774 :Only one cable lift hill allowed per ride STR_1775 :Off STR_1776 :On -STR_1777 :{WINDOW_COLOUR_2}Music: +STR_1777 :{WINDOW_COLOUR_2}Music STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Pandakosztüm STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigriskosztüm @@ -2342,7 +2342,7 @@ STR_2337 :Német márka (DM) STR_2338 :Jen ({YEN}) STR_2339 :Pezeta (Pts) STR_2340 :Líra (L) -STR_2341 :Gulden (Dfl.) +STR_2341 :Gulden (fl.) STR_2342 :Korona (kr) STR_2343 :Euró ({EURO}) STR_2344 :Birodalmi @@ -2681,37 +2681,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Never +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. STR_2711 :; STR_2712 := STR_2713 :, @@ -2719,48 +2719,48 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(up) +STR_2719 :(new file) +STR_2720 :{UINT16}sec +STR_2721 :{UINT16}secs +STR_2722 :{UINT16}min:{UINT16}sec +STR_2723 :{UINT16}min:{UINT16}secs +STR_2724 :{UINT16}mins:{UINT16}sec +STR_2725 :{UINT16}mins:{UINT16}secs +STR_2726 :{UINT16}min +STR_2727 :{UINT16}mins +STR_2728 :{UINT16}hour:{UINT16}min +STR_2729 :{UINT16}hour:{UINT16}mins +STR_2730 :{UINT16}hours:{UINT16}min +STR_2731 :{UINT16}hours:{UINT16}mins +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Year {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Year {COMMA16} +STR_2738 :Title screen music: +STR_2739 :None +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat not found +STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat in your RCT2 installation. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? -STR_2757 :??? -STR_2758 :??? -STR_2759 :??? +STR_2749 :My new scenario +STR_2750 :Move all items to top +STR_2751 :Move all items to bottom +STR_2752 :Clear grass +STR_2753 :Mowed grass +STR_2754 :Water plants +STR_2755 :Fix vandalism +STR_2756 :Remove litter +STR_2757 :Force Sun +STR_2758 :Force Thunder +STR_2759 :Zero Clearance # New strings used in the cheats window previously these were ??? STR_2760 :+5K Money STR_2761 :Pay For Entrance @@ -2768,7 +2768,7 @@ STR_2762 :Pay For Rides STR_2763 :??? STR_2764 :Happy Guests STR_2765 :Large Tram -STR_2766 :??? +STR_2766 :Win scenario STR_2767 :Freeze Climate STR_2768 :Unfreeze Climate STR_2769 :Open Park @@ -2778,12 +2778,12 @@ STR_2772 :Faster Gamespeed STR_2773 :Windowed STR_2774 :Fullscreen STR_2775 :Fullscreen (desktop) -STR_2776 :Nyelv +STR_2776 :Nyelv: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings -STR_2779 :??? -STR_2780 :??? +STR_2779 :Viewport #{COMMA16} +STR_2780 :Extra viewport STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + @@ -3450,3 +3450,164 @@ STR_3443 :Page 4 STR_3444 :Page 5 STR_3445 :Set Patrol Area STR_3446 :Cancel Patrol Area +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renew rides +STR_5124 :No Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +#Thousands separator +STR_5151 :. +#Decimal separator +STR_5152 :, +STR_5153 :Colour schemes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpaths +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear diff --git a/data/language/italian.txt b/data/language/italian.txt new file mode 100644 index 0000000000..f35da40480 --- /dev/null +++ b/data/language/italian.txt @@ -0,0 +1,3613 @@ +# STR_XXXX part is read and XXXX becomes the string id number. +# Everything after the colon and before the new line will be saved as the string. +# Use # at the beginning of a line to leave a comment. +STR_0000 : +STR_0001 :{STRINGID} {COMMA16} +STR_0002 :Attrazione +STR_0003 :Attrazione +STR_0004 :Attrazione oscillante +STR_0005 :Attrazione +STR_0006 :Ottovolante per giovanissimi +STR_0007 :Ferrovia in miniatura +STR_0008 :Monorotaia +STR_0009 :Mini-attrazione sospesa +STR_0010 :Attrazione +STR_0011 :Attrazione +STR_0012 :Attrazione +STR_0013 :Attrazione su carrozza +STR_0014 :Attrazione +STR_0015 :Attrazione +STR_0016 :Attrazione +STR_0017 :Ottovolante con giro d. morte +STR_0018 :Attrazione +STR_0019 :Attrazione +STR_0020 :Seggiovia +STR_0021 :Attrazione +STR_0022 :Attrazione +STR_0023 :Attrazione +STR_0024 :Attrazione +STR_0025 :Attrazione +STR_0026 :Attrazione +STR_0027 :Attrazione +STR_0028 :Attrazione +STR_0029 :Attrazione +STR_0030 :Chiosco +STR_0031 :Chiosco +STR_0032 :Chiosco +STR_0033 :Chiosco +STR_0034 :Chiosco +STR_0035 :Attrazione +STR_0036 :Chiosco +STR_0037 :Chiosco +STR_0038 :Servizi igienici +STR_0039 :Attrazione +STR_0040 :Attrazione +STR_0041 :Attrazione +STR_0042 :Attrazione +STR_0043 :Attrazione +STR_0044 :Attraz. a caduta libera rov. +STR_0045 :Traino +STR_0046 :Attrazione +STR_0047 :Attrazione +STR_0048 :Attrazione +STR_0049 :Attrazione +STR_0050 :Attrazione +STR_0051 :Attrazione +STR_0052 :Attrazione +STR_0053 :Ottov. super-serpentina +STR_0054 :Ottovolante di legno +STR_0055 :Ottov. a frizione laterale +STR_0056 :Topo tutto matto +STR_0057 :Ottov. multi-dimensionale +STR_0058 :Attrazione +STR_0059 :Ottovolante aereo invertito +STR_0060 :Attrazione +STR_0061 :Attrazione +STR_0062 :Attrazione +STR_0063 :Attrazione +STR_0064 :Attrazione +STR_0065 :Monorotaia sospesa +STR_0066 :Attrazione +STR_0067 :Attrazione +STR_0068 :Serpentone volante +STR_0069 :Attrazione +STR_0070 :Attrazione +STR_0071 :Attrazione +STR_0072 :Attrazione +STR_0073 :Attrazione +STR_0074 :Attrazione +STR_0075 :Attrazione +STR_0076 :Attrazione acquatica +STR_0077 :Attrazione +STR_0078 :Attrazione +STR_0079 :Attrazione +STR_0080 :Attrazione +STR_0081 :Attrazione +STR_0082 :Attrazione +STR_0083 :Attrazione +STR_0084 :Attrazione +STR_0085 :Attrazione +STR_0086 :Attrazione +STR_0087 :Attrazione +STR_0088 :Attrazione +STR_0089 :Mini-ottovolante +STR_0090 :Attrazione +STR_0091 :Attrazione +STR_0092 :Attrazione +STR_0093 : +STR_0094 : +STR_0095 : +STR_0096 : +STR_0097 : +STR_0098 : +STR_0099 : +STR_0100 : +STR_0101 : +STR_0102 : +STR_0103 : +STR_0104 : +STR_0105 : +STR_0106 : +STR_0107 : +STR_0108 : +STR_0109 : +STR_0110 : +STR_0111 : +STR_0112 : +STR_0113 : +STR_0114 : +STR_0115 : +STR_0116 : +STR_0117 : +STR_0118 : +STR_0119 : +STR_0120 : +STR_0121 : +STR_0122 : +STR_0123 : +STR_0124 : +STR_0125 : +STR_0126 : +STR_0127 : +STR_0128 : +STR_0129 : +STR_0130 : +STR_0131 : +STR_0132 : +STR_0133 : +STR_0134 : +STR_0135 : +STR_0136 : +STR_0137 : +STR_0138 : +STR_0139 : +STR_0140 : +STR_0141 : +STR_0142 : +STR_0143 : +STR_0144 : +STR_0145 : +STR_0146 : +STR_0147 : +STR_0148 : +STR_0149 : +STR_0150 : +STR_0151 : +STR_0152 : +STR_0153 : +STR_0154 : +STR_0155 : +STR_0156 : +STR_0157 : +STR_0158 : +STR_0159 : +STR_0160 : +STR_0161 : +STR_0162 : +STR_0163 : +STR_0164 : +STR_0165 : +STR_0166 : +STR_0167 : +STR_0168 : +STR_0169 : +STR_0170 : +STR_0171 : +STR_0172 : +STR_0173 : +STR_0174 : +STR_0175 : +STR_0176 : +STR_0177 : +STR_0178 : +STR_0179 : +STR_0180 : +STR_0181 : +STR_0182 : +STR_0183 : +STR_0184 : +STR_0185 : +STR_0186 : +STR_0187 : +STR_0188 : +STR_0189 : +STR_0190 : +STR_0191 : +STR_0192 : +STR_0193 : +STR_0194 : +STR_0195 : +STR_0196 : +STR_0197 : +STR_0198 : +STR_0199 : +STR_0200 : +STR_0201 : +STR_0202 : +STR_0203 : +STR_0204 : +STR_0205 : +STR_0206 : +STR_0207 : +STR_0208 : +STR_0209 : +STR_0210 : +STR_0211 : +STR_0212 : +STR_0213 : +STR_0214 : +STR_0215 : +STR_0216 : +STR_0217 : +STR_0218 : +STR_0219 : +STR_0220 : +STR_0221 : +STR_0222 : +STR_0223 : +STR_0224 : +STR_0225 : +STR_0226 : +STR_0227 : +STR_0228 : +STR_0229 : +STR_0230 : +STR_0231 : +STR_0232 : +STR_0233 : +STR_0234 : +STR_0235 : +STR_0236 : +STR_0237 : +STR_0238 : +STR_0239 : +STR_0240 : +STR_0241 : +STR_0242 : +STR_0243 : +STR_0244 : +STR_0245 : +STR_0246 : +STR_0247 : +STR_0248 : +STR_0249 : +STR_0250 : +STR_0251 : +STR_0252 : +STR_0253 : +STR_0254 : +STR_0255 : +STR_0256 : +STR_0257 : +STR_0258 : +STR_0259 : +STR_0260 : +STR_0261 : +STR_0262 : +STR_0263 : +STR_0264 : +STR_0265 : +STR_0266 : +STR_0267 : +STR_0268 : +STR_0269 : +STR_0270 : +STR_0271 : +STR_0272 : +STR_0273 : +STR_0274 : +STR_0275 : +STR_0276 : +STR_0277 : +STR_0278 : +STR_0279 : +STR_0280 : +STR_0281 : +STR_0282 : +STR_0283 : +STR_0284 : +STR_0285 : +STR_0286 : +STR_0287 : +STR_0288 : +STR_0289 : +STR_0290 : +STR_0291 : +STR_0292 : +STR_0293 : +STR_0294 : +STR_0295 : +STR_0296 : +STR_0297 : +STR_0298 : +STR_0299 : +STR_0300 : +STR_0301 : +STR_0302 : +STR_0303 : +STR_0304 : +STR_0305 : +STR_0306 : +STR_0307 : +STR_0308 : +STR_0309 : +STR_0310 : +STR_0311 : +STR_0312 : +STR_0313 : +STR_0314 : +STR_0315 : +STR_0316 : +STR_0317 : +STR_0318 : +STR_0319 : +STR_0320 : +STR_0321 : +STR_0322 : +STR_0323 : +STR_0324 : +STR_0325 : +STR_0326 : +STR_0327 : +STR_0328 : +STR_0329 : +STR_0330 : +STR_0331 : +STR_0332 : +STR_0333 : +STR_0334 : +STR_0335 : +STR_0336 : +STR_0337 : +STR_0338 : +STR_0339 : +STR_0340 : +STR_0341 : +STR_0342 : +STR_0343 : +STR_0344 : +STR_0345 : +STR_0346 : +STR_0347 : +STR_0348 : +STR_0349 : +STR_0350 : +STR_0351 : +STR_0352 : +STR_0353 : +STR_0354 : +STR_0355 : +STR_0356 : +STR_0357 : +STR_0358 : +STR_0359 : +STR_0360 : +STR_0361 : +STR_0362 : +STR_0363 : +STR_0364 : +STR_0365 : +STR_0366 : +STR_0367 : +STR_0368 : +STR_0369 : +STR_0370 : +STR_0371 : +STR_0372 : +STR_0373 : +STR_0374 : +STR_0375 : +STR_0376 : +STR_0377 : +STR_0378 : +STR_0379 : +STR_0380 : +STR_0381 : +STR_0382 : +STR_0383 : +STR_0384 : +STR_0385 : +STR_0386 : +STR_0387 : +STR_0388 : +STR_0389 : +STR_0390 : +STR_0391 : +STR_0392 : +STR_0393 : +STR_0394 : +STR_0395 : +STR_0396 : +STR_0397 : +STR_0398 : +STR_0399 : +STR_0400 : +STR_0401 : +STR_0402 : +STR_0403 : +STR_0404 : +STR_0405 : +STR_0406 : +STR_0407 : +STR_0408 : +STR_0409 : +STR_0410 : +STR_0411 : +STR_0412 : +STR_0413 : +STR_0414 : +STR_0415 : +STR_0416 : +STR_0417 : +STR_0418 : +STR_0419 : +STR_0420 : +STR_0421 : +STR_0422 : +STR_0423 : +STR_0424 : +STR_0425 : +STR_0426 : +STR_0427 : +STR_0428 : +STR_0429 : +STR_0430 : +STR_0431 : +STR_0432 : +STR_0433 : +STR_0434 : +STR_0435 : +STR_0436 : +STR_0437 : +STR_0438 : +STR_0439 : +STR_0440 : +STR_0441 : +STR_0442 : +STR_0443 : +STR_0444 : +STR_0445 : +STR_0446 : +STR_0447 : +STR_0448 : +STR_0449 : +STR_0450 : +STR_0451 : +STR_0452 : +STR_0453 : +STR_0454 : +STR_0455 : +STR_0456 : +STR_0457 : +STR_0458 : +STR_0459 : +STR_0460 : +STR_0461 : +STR_0462 : +STR_0463 : +STR_0464 : +STR_0465 : +STR_0466 : +STR_0467 : +STR_0468 : +STR_0469 : +STR_0470 : +STR_0471 : +STR_0472 : +STR_0473 : +STR_0474 : +STR_0475 : +STR_0476 : +STR_0477 : +STR_0478 : +STR_0479 : +STR_0480 : +STR_0481 : +STR_0482 : +STR_0483 : +STR_0484 : +STR_0485 : +STR_0486 : +STR_0487 : +STR_0488 : +STR_0489 : +STR_0490 : +STR_0491 : +STR_0492 : +STR_0493 : +STR_0494 : +STR_0495 : +STR_0496 : +STR_0497 : +STR_0498 : +STR_0499 : +STR_0500 : +STR_0501 : +STR_0502 : +STR_0503 : +STR_0504 : +STR_0505 : +STR_0506 : +STR_0507 : +STR_0508 : +STR_0509 : +STR_0510 : +STR_0511 : +STR_0512 : +STR_0513 : +STR_0514 :I treni, sospesi sotto l'ottovolante, durante le curve oscillano lateralmente +STR_0515 : +STR_0516 :Un ottovolante tranquillo, per chi non ha ancora il coraggio di affrontare le attrazioni più impegnative +STR_0517 :I passeggeri viaggiano su treni in miniatura su una strada ferrata di dimensioni ridotte +STR_0518 :I passeggeri viaggiano su treni elettrici lungo un tracciato monorotaia +STR_0519 :I passeggeri viaggiano a bordo di piccole carrozze appese al circuito, oscillando liberamente da lato a lato a ogni curva +STR_0520 : +STR_0521 : +STR_0522 : +STR_0523 :I passeggeri viaggiano lentamente su veicoli elettrici lungo un percorso basato su un circuito +STR_0524 : +STR_0525 : +STR_0526 : +STR_0527 :Un rapido ottovolante d'acciaio caratterizzato da cadute verticali +STR_0528 : +STR_0529 : +STR_0530 :Le carrozze pendono da un cavo d'acciaio che fa avanti e indietro per tutto il tracciato +STR_0531 : +STR_0532 : +STR_0533 : +STR_0534 : +STR_0535 : +STR_0536 : +STR_0537 : +STR_0538 : +STR_0539 : +STR_0540 : +STR_0541 : +STR_0542 : +STR_0543 : +STR_0544 : +STR_0545 : +STR_0546 : +STR_0547 : +STR_0548 : +STR_0549 : +STR_0550 : +STR_0551 : +STR_0552 : +STR_0553 : +STR_0554 :La carrozza acquista accelerazione a partire dalla stazione attraverso un lungo tratto pianeggiante grazie a dei motori a induzione lineare, quindi percorre una ripida salita per poi scendere in caduta libera e tornare alla stazione +STR_0555 : +STR_0556 : +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 : +STR_0563 :Seduti comodamente - il solo limite è che si può effettuare un solo giro alla volta - i passeggeri sperimentano dolci discese e numerose curve, sperimentando una piacevole sensazione di assenza di peso +STR_0564 :Quest'attrazione, in cui si viaggia lungo un tracciato di legno, è veloce, ricca di imprevisti, rumorosa e dà al passeggero la sensazione di essere senza controllo, oltre che quella di una grande libertà +STR_0565 :Un semplice ottovolante di legno, adatto solo a curve e declivi lenti, in cui le carrozze sono tenute in pista solo dalla frizione delle ruote sui i bordi della pista e dalla gravità +STR_0566 :Carrozze individuali sfrecciano per uno stretto percorso a zig-zag con curve molto strette e corte e ripide discese +STR_0567 :Seduti su sedili sospesi a entrambi i lati del tracciato, i passeggeri vengono capovolti mentre si tuffano per rapide discese e sperimentano numerose inversioni +STR_0568 : +STR_0569 :I passeggeri, cinti da speciali imbracature al di sotto il tracciato, sperimentano la sensazione del volo quando vengono fatti oscillare nell'aria +STR_0570 : +STR_0571 : +STR_0572 : +STR_0573 : +STR_0574 : +STR_0575 :Dei treni elettrici sospesi sotto una singola rotaia trasportano i passeggeri per tutto il parco +STR_0576 : +STR_0577 : +STR_0578 :Le carrozze corrono per il tracciato caratterizzato da vari giri, ripide discese e curve ondulanti +STR_0579 : +STR_0580 : +STR_0581 : +STR_0582 : +STR_0583 : +STR_0584 : +STR_0585 : +STR_0586 :Carrozze a forma di barca viaggiano lungo l'ottovolante, caratterizzato da ripide discese, curve avvitate e tuffi in sezioni acquatiche più tranquille. +STR_0587 : +STR_0588 : +STR_0589 : +STR_0590 : +STR_0591 : +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 : +STR_0599 :Un ottovolante compatto con carrozze individuali e rapide curve in discesa +STR_0600 : +STR_0601 : +STR_0602 : +STR_0603 :Visitatore {INT32} +STR_0604 :Visitatore {INT32} +STR_0605 :Visitatore {INT32} +STR_0606 :Visitatore {INT32} +STR_0607 :Visitatore {INT32} +STR_0608 :Visitatore {INT32} +STR_0609 :Visitatore {INT32} +STR_0610 :Visitatore {INT32} +STR_0611 :Visitatore {INT32} +STR_0612 :Visitatore {INT32} +STR_0613 :Visitatore {INT32} +STR_0614 :Visitatore {INT32} +STR_0615 :Visitatore {INT32} +STR_0616 :Visitatore {INT32} +STR_0617 :Visitatore {INT32} +STR_0618 :Visitatore {INT32} +STR_0619 :Visitatore {INT32} +STR_0620 :Visitatore {INT32} +STR_0621 :Visitatore {INT32} +STR_0622 :Visitatore {INT32} +STR_0623 :Visitatore {INT32} +STR_0624 :Visitatore {INT32} +STR_0625 :Visitatore {INT32} +STR_0626 :Visitatore {INT32} +STR_0627 :Visitatore {INT32} +STR_0628 :Visitatore {INT32} +STR_0629 :Visitatore {INT32} +STR_0630 :Visitatore {INT32} +STR_0631 :Visitatore {INT32} +STR_0632 :Visitatore {INT32} +STR_0633 :Visitatore {INT32} +STR_0634 :Visitatore {INT32} +STR_0635 :Visitatore {INT32} +STR_0636 :Visitatore {INT32} +STR_0637 :Visitatore {INT32} +STR_0638 :Visitatore {INT32} +STR_0639 :Visitatore {INT32} +STR_0640 :Visitatore {INT32} +STR_0641 :Visitatore {INT32} +STR_0642 :Visitatore {INT32} +STR_0643 :Visitatore {INT32} +STR_0644 :Visitatore {INT32} +STR_0645 :Visitatore {INT32} +STR_0646 :Visitatore {INT32} +STR_0647 :Visitatore {INT32} +STR_0648 :Visitatore {INT32} +STR_0649 :Visitatore {INT32} +STR_0650 :Visitatore {INT32} +STR_0651 :Visitatore {INT32} +STR_0652 :Visitatore {INT32} +STR_0653 :Visitatore {INT32} +STR_0654 :Visitatore {INT32} +STR_0655 :Visitatore {INT32} +STR_0656 :Visitatore {INT32} +STR_0657 :Visitatore {INT32} +STR_0658 :Visitatore {INT32} +STR_0659 :Visitatore {INT32} +STR_0660 :Visitatore {INT32} +STR_0661 :Visitatore {INT32} +STR_0662 :Visitatore {INT32} +STR_0663 :Visitatore {INT32} +STR_0664 :Visitatore {INT32} +STR_0665 :Visitatore {INT32} +STR_0666 :Visitatore {INT32} +STR_0667 :Visitatore {INT32} +STR_0668 :Visitatore {INT32} +STR_0669 :Visitatore {INT32} +STR_0670 :Visitatore {INT32} +STR_0671 :Visitatore {INT32} +STR_0672 :Visitatore {INT32} +STR_0673 :Visitatore {INT32} +STR_0674 :Visitatore {INT32} +STR_0675 :Visitatore {INT32} +STR_0676 :Visitatore {INT32} +STR_0677 :Visitatore {INT32} +STR_0678 :Visitatore {INT32} +STR_0679 :Visitatore {INT32} +STR_0680 :Visitatore {INT32} +STR_0681 :Visitatore {INT32} +STR_0682 :Visitatore {INT32} +STR_0683 :Visitatore {INT32} +STR_0684 :Visitatore {INT32} +STR_0685 :Visitatore {INT32} +STR_0686 :Visitatore {INT32} +STR_0687 :Visitatore {INT32} +STR_0688 :Visitatore {INT32} +STR_0689 :Visitatore {INT32} +STR_0690 :Visitatore {INT32} +STR_0691 :Visitatore {INT32} +STR_0692 :Visitatore {INT32} +STR_0693 :Visitatore {INT32} +STR_0694 :Visitatore {INT32} +STR_0695 :Visitatore {INT32} +STR_0696 :Visitatore {INT32} +STR_0697 :Visitatore {INT32} +STR_0698 :Visitatore {INT32} +STR_0699 :Visitatore {INT32} +STR_0700 :Visitatore {INT32} +STR_0701 :Visitatore {INT32} +STR_0702 :Visitatore {INT32} +STR_0703 :Visitatore {INT32} +STR_0704 :Visitatore {INT32} +STR_0705 :Visitatore {INT32} +STR_0706 :Visitatore {INT32} +STR_0707 :Visitatore {INT32} +STR_0708 :Visitatore {INT32} +STR_0709 :Visitatore {INT32} +STR_0710 :Visitatore {INT32} +STR_0711 :Visitatore {INT32} +STR_0712 :Visitatore {INT32} +STR_0713 :Visitatore {INT32} +STR_0714 :Visitatore {INT32} +STR_0715 :Visitatore {INT32} +STR_0716 :Visitatore {INT32} +STR_0717 :Visitatore {INT32} +STR_0718 :Visitatore {INT32} +STR_0719 :Visitatore {INT32} +STR_0720 :Visitatore {INT32} +STR_0721 :Visitatore {INT32} +STR_0722 :Visitatore {INT32} +STR_0723 :Visitatore {INT32} +STR_0724 :Visitatore {INT32} +STR_0725 :Visitatore {INT32} +STR_0726 :Visitatore {INT32} +STR_0727 :Visitatore {INT32} +STR_0728 :Visitatore {INT32} +STR_0729 :Visitatore {INT32} +STR_0730 :Visitatore {INT32} +STR_0731 :Visitatore {INT32} +STR_0732 :Visitatore {INT32} +STR_0733 :Visitatore {INT32} +STR_0734 :Visitatore {INT32} +STR_0735 :Visitatore {INT32} +STR_0736 :Visitatore {INT32} +STR_0737 :Visitatore {INT32} +STR_0738 :Visitatore {INT32} +STR_0739 :Visitatore {INT32} +STR_0740 :Visitatore {INT32} +STR_0741 :Visitatore {INT32} +STR_0742 :Visitatore {INT32} +STR_0743 :Visitatore {INT32} +STR_0744 :Visitatore {INT32} +STR_0745 :Visitatore {INT32} +STR_0746 :Visitatore {INT32} +STR_0747 :Visitatore {INT32} +STR_0748 :Visitatore {INT32} +STR_0749 :Visitatore {INT32} +STR_0750 :Visitatore {INT32} +STR_0751 :Visitatore {INT32} +STR_0752 :Visitatore {INT32} +STR_0753 :Visitatore {INT32} +STR_0754 :Visitatore {INT32} +STR_0755 :Visitatore {INT32} +STR_0756 :Visitatore {INT32} +STR_0757 :Visitatore {INT32} +STR_0758 :Visitatore {INT32} +STR_0759 :Visitatore {INT32} +STR_0760 :Visitatore {INT32} +STR_0761 :Visitatore {INT32} +STR_0762 :Visitatore {INT32} +STR_0763 :Visitatore {INT32} +STR_0764 :Visitatore {INT32} +STR_0765 :Visitatore {INT32} +STR_0766 :Visitatore {INT32} +STR_0767 :Visitatore {INT32} +STR_0768 :Tuttofare {INT32} +STR_0769 :Meccanico {INT32} +STR_0770 :Vigilante {INT32} +STR_0771 :Intrattenitore {INT32} +STR_0772 :Parco senza nome{POP16}{POP16} +STR_0773 :Parco senza nome{POP16}{POP16} +STR_0774 :Parco senza nome{POP16}{POP16} +STR_0775 :Parco senza nome{POP16}{POP16} +STR_0776 :Parco senza nome{POP16}{POP16} +STR_0777 :Parco senza nome{POP16}{POP16} +STR_0778 :Cartello +STR_0779 :1{DEGREE} +STR_0780 :2{DEGREE} +STR_0781 :3{DEGREE} +STR_0782 :4{DEGREE} +STR_0783 :5{DEGREE} +STR_0784 :6{DEGREE} +STR_0785 :7{DEGREE} +STR_0786 :8{DEGREE} +STR_0787 :9{DEGREE} +STR_0788 :10{DEGREE} +STR_0789 :11{DEGREE} +STR_0790 :12{DEGREE} +STR_0791 :13{DEGREE} +STR_0792 :14{DEGREE} +STR_0793 :15{DEGREE} +STR_0794 :16{DEGREE} +STR_0795 :17{DEGREE} +STR_0796 :18{DEGREE} +STR_0797 :19{DEGREE} +STR_0798 :20{DEGREE} +STR_0799 :21{DEGREE} +STR_0800 :22{DEGREE} +STR_0801 :23{DEGREE} +STR_0802 :24{DEGREE} +STR_0803 :25{DEGREE} +STR_0804 :26{DEGREE} +STR_0805 :27{DEGREE} +STR_0806 :28{DEGREE} +STR_0807 :29{DEGREE} +STR_0808 :30{DEGREE} +STR_0809 :31{DEGREE} +STR_0810 :Gen +STR_0811 :Feb +STR_0812 :Mar +STR_0813 :Apr +STR_0814 :Mag +STR_0815 :Giu +STR_0816 :Lug +STR_0817 :Ago +STR_0818 :Set +STR_0819 :Ott +STR_0820 :Nov +STR_0821 :Dic +STR_0822 :Impossibile accedere ai file della grafica +STR_0823 :File mancante o inaccessibile +STR_0824 :{BLACK}{CROSS} +STR_0825 :Il nome scelto è già in uso +STR_0826 :I nomi stabiliti sono troppi +STR_0827 :Denaro insufficiente - Costo: {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}Chiudi la finestra +STR_0829 :{SMALLFONT}{BLACK}Titolo della finestra - Trascina questo per spostare la finestra +STR_0830 :{SMALLFONT}{BLACK}Zoom in avanti +STR_0831 :{SMALLFONT}{BLACK}Zoom indietro +STR_0832 :{SMALLFONT}{BLACK}Ruota di 90{DEGREE} in senso orario +STR_0833 :{SMALLFONT}{BLACK}Metti in pausa +STR_0834 :{SMALLFONT}{BLACK}Opzioni di gioco e del disco +STR_0835 :Inizializzazione del gioco fallita +STR_0836 :Impossibile iniziare la partita se la finestra è ridotta a icona +STR_0837 :Impossibile inizializzare il sistema grafico +STR_0838 :Il codice CD {INT32} del CD del tuo RollerCoaster Tycoon 2 è errato!{WINDOW_COLOUR_1}{WINDOW_COLOUR_1}Disinstalla RollerCoaster Tycoon 2% e installalo di nuovo digitando il codice CD corretto +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +STR_0841 :Finestra sul desktop +STR_0842 :640x480 schermo intero +STR_0843 :800x600 schermo intero +STR_0844 :1024x768 schermo intero +STR_0845 :1152x864 schermo intero +STR_0846 :1280x1024 schermo intero +STR_0847 :Informazioni su 'RollerCoaster Tycoon 2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}Versione 2.01.032 +STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, tutti i diritti riservati +STR_0851 :{WINDOW_COLOUR_2}Design e programmazione di Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Grafica di Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Effetti sonori e musica di Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Audio aggiuntivo registrato da David Ellis +STR_0855 :{WINDOW_COLOUR_2}Rappresentazione di Jacqui Lyons a Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}Grazie a: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth e John Wardley +STR_0858 :{WINDOW_COLOUR_2} +STR_0859 :{WINDOW_COLOUR_2} +STR_0860 :{WINDOW_COLOUR_2} +STR_0861 : +STR_0862 : +STR_0863 : +STR_0864 : +STR_0865 :{STRINGID} +STR_0866 :{POP16}{STRINGID} +STR_0867 :{POP16}{POP16}{STRINGID} +STR_0868 :{POP16}{POP16}{POP16}{STRINGID} +STR_0869 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0870 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0872 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0873 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0874 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0875 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0876 :{BLACK}{DOWN} +STR_0877 :Troppo basso!! +STR_0878 :Troppo alto!! +STR_0879 :Non posso abbassare il terreno in questo punto... +STR_0880 :Non posso innalzare il terreno in questo punto... +STR_0881 :Un oggetto è d'intralcio +STR_0882 :Carica la partita +STR_0883 :Salva la partita +STR_0884 :Carica un paesaggio +STR_0885 :Salva un paesaggio +STR_0886 :Abbandona la partita +STR_0887 :Abbandona l'editor degli scenari +STR_0888 :Abbandona la progettazione degli ottovolanti +STR_0889 :Abbandona il programma di progettazione dei tracciati +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :Schermata +STR_0892 :Schermata salvata su disco come '{STRINGID}' +STR_0893 :Cattura della schermata fallita!! +STR_0894 :Area dati per i paesaggi piena!! +STR_0895 :Non si può costruire contemporaneamente sopra e sotto il livello del terreno +STR_0896 :{POP16}{POP16}{STRINGID} Costruzione +STR_0897 :Direzione +STR_0898 :{SMALLFONT}{BLACK}Curva a sinistra +STR_0899 :{SMALLFONT}{BLACK}Curva a destra +STR_0900 :{SMALLFONT}{BLACK}Curva a sinistra (a piccolo raggio) +STR_0901 :{SMALLFONT}{BLACK}Curva a destra (a piccolo raggio) +STR_0902 :{SMALLFONT}{BLACK}Curva a sinistra (a raggio molto piccolo) +STR_0903 :{SMALLFONT}{BLACK}Curva a destra (a raggio molto piccolo) +STR_0904 :{SMALLFONT}{BLACK}Curva a sinistra (a largo raggio) +STR_0905 :{SMALLFONT}{BLACK}Curva a destra (a largo raggio) +STR_0906 :{SMALLFONT}{BLACK}Linea retta +STR_0907 :Pendio +STR_0908 :Inclinazione +STR_0909 :Rot. sedile +STR_0910 :{SMALLFONT}{BLACK}Inclina per una curva a sinistra +STR_0911 :{SMALLFONT}{BLACK}Inclina per una curva a destra +STR_0912 :{SMALLFONT}{BLACK}Nessuna inclinazione +STR_0913 :{SMALLFONT}{BLACK}Torna alla sezione precedente +STR_0914 :{SMALLFONT}{BLACK}Vai alla sezione successiva +STR_0915 :{SMALLFONT}{BLACK}Costruisci la sezione selezionata +STR_0916 :{SMALLFONT}{BLACK}Cancella la sezione evidenziata +STR_0917 :{SMALLFONT}{BLACK}Caduta verticale +STR_0918 :{SMALLFONT}{BLACK}Pendio ripido +STR_0919 :{SMALLFONT}{BLACK}Pendio +STR_0920 :{SMALLFONT}{BLACK}Livello +STR_0921 :{SMALLFONT}{BLACK}Salita +STR_0922 :{SMALLFONT}{BLACK}Salita ripida +STR_0923 :{SMALLFONT}{BLACK}Salita verticale +STR_0924 :{SMALLFONT}{BLACK}Elica verso il basso +STR_0925 :{SMALLFONT}{BLACK}Elica verso l'alto +STR_0926 :Non posso rimuoverlo... +STR_0927 :Non posso costruirlo qui... +STR_0928 :{SMALLFONT}{BLACK}Catena da traino, per spostare le carrozze lungo le salite +STR_0929 :Curva a 'S' (sinistra) +STR_0930 :Curva a 'S' (destra) +STR_0931 :Giro verticale (sx) +STR_0932 :Giro verticale (dx) +STR_0933 :Prima devi modificare l'altezza del terreno +STR_0934 :L'entrata dell'attrazione è d'intralcio +STR_0935 :L'uscita dell'attrazione è d'intralcio +STR_0936 :L'entrata del parco è d'intralcio +STR_0937 :{SMALLFONT}{BLACK}Visualizza le opzioni +STR_0938 :{SMALLFONT}{BLACK}Regola l'altezza e la pendenza del terreno +STR_0939 :Visuale sotterranea/interna +STR_0940 :Rimuove il terreno della base +STR_0941 :Rimuove le pareti verticali +STR_0942 :Attrazioni trasparenti +STR_0943 :Scenario trasparente +STR_0944 :Salva +STR_0945 :Non salv. +STR_0946 :Annulla +STR_0947 :Salvare prima di caricare? +STR_0948 :Salvare prima di uscire? +STR_0949 :Salvare prima di uscire? +STR_0950 :Carica una partita +STR_0951 :Esci dal gioco +STR_0952 :Esci dal gioco +STR_0953 :Carica un paesaggio +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}Seleziona l'angolo di rotazione dei sedili in questa sezione del tracciato +STR_0956 :-180{DEGREE} +STR_0957 :-135{DEGREE} +STR_0958 :-90{DEGREE} +STR_0959 :-45{DEGREE} +STR_0960 :0{DEGREE} +STR_0961 :+45{DEGREE} +STR_0962 :+90{DEGREE} +STR_0963 :+135{DEGREE} +STR_0964 :+180{DEGREE} +STR_0965 :+225{DEGREE} +STR_0966 :+270{DEGREE} +STR_0967 :+315{DEGREE} +STR_0968 :+360{DEGREE} +STR_0969 :+405{DEGREE} +STR_0970 :+450{DEGREE} +STR_0971 :+495{DEGREE} +STR_0972 :Annulla +STR_0973 :OK +STR_0974 :Attrazioni +STR_0975 :Negozi e chioschi +STR_0976 :Servizi igienici e uffici informazione +STR_0977 :Nuove attrazioni di trasporto +STR_0978 :Nuove attrazioni tranquille +STR_0979 :Nuovi ottovolanti +STR_0980 :Nuove attrazioni eccitanti +STR_0981 :Nuove attrazioni acquatiche +STR_0982 :Nuovi negozi e chioschi +STR_0983 :Ricerca & Sviluppo +STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +STR_0987 :Troppe attrazioni +STR_0988 :Impossibile creare nuove attrazioni... +STR_0989 :{STRINGID} +STR_0990 :{SMALLFONT}{BLACK}Costruzione +STR_0991 :Piattaforma stazione +STR_0992 :{SMALLFONT}{BLACK}Demolisci l'intera attrazione +STR_0993 :Demolisci l'attrazione +STR_0994 :Demolisci +STR_0995 :{WINDOW_COLOUR_1}Sei sicuro di voler demolire completamente {STRINGID}? +STR_0996 :Visuale generale +STR_0997 :{SMALLFONT}{BLACK}Seleziona la visuale +STR_0998 :Non è possibile collocare altre stazioni per questa attrazione +STR_0999 :È necessaria una piattaforma +STR_1000 :Il tracciato non costituisce un circuito completo +STR_1001 :Il tracciato non è adatto al tipo di treno +STR_1002 :Impossibile aprire {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :Impossibile provare {POP16}{POP16}{POP16}{STRINGID}... +STR_1004 :Impossibile chiudere {POP16}{POP16}{POP16}{STRINGID}... +STR_1005 :Impossibile iniziare la costruzione su {POP16}{POP16}{POP16}{STRINGID}... +STR_1006 :Prima dev'essere chiusa/o +STR_1007 :Impossibile creare veicoli a sufficienza +STR_1008 :{SMALLFONT}{BLACK}Apri, chiudi o prova un'attrazione +STR_1009 :{SMALLFONT}{BLACK}Apri o chiudi tutte le attrazioni +STR_1010 :{SMALLFONT}{BLACK}Apri o chiudi il parco +STR_1011 :Chiudi tutto +STR_1012 :Apri tutto +STR_1013 :Chiudi il parco +STR_1014 :Apri il parco +STR_1015 :Impossibile operare con più di una piattaforma in questa modalità +STR_1016 :Impossibile operare con meno di due stazioni in questa modalità +STR_1017 :Impossibile cambiare la modalità operativa... +STR_1018 :Impossibile effettuare modifiche... +STR_1019 :Impossibile effettuare modifiche... +STR_1020 :Impossibile effettuare modifiche... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} carrozza per treno +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} carrozze per treno +STR_1024 :{COMMA16} carrozza per treno +STR_1025 :{COMMA16} carrozze per treno +STR_1026 :Piattaforma della stazione troppo lunga!! +STR_1027 :{SMALLFONT}{BLACK}Individualo nella visuale principale +STR_1028 :Fuori dalla mappa!! +STR_1029 :Non si può costruire contemporaneamente sopra e sotto l'acqua!! +STR_1030 :Si può costruire solo sott'acqua!! +STR_1031 :Non può essere costruito sott'acqua!! +STR_1032 :Si può costruire solo sopra l'acqua!! +STR_1033 :Si può costruire solo sopra il terreno!! +STR_1034 :Si può costruire solo sul terreno!! +STR_1035 :Le autorità locali non permetteranno la costruzione a un'altezza superiore alle cime degli alberi!! +STR_1036 :Carica una partita +STR_1037 :Carica un paesaggio +STR_1038 :Converti la partita salvata in uno scenario +STR_1039 :Installa un nuovo design del tracciato +STR_1040 :Salva la partita +STR_1041 :Salva lo scenario +STR_1042 :Salva il paesaggio +STR_1043 :Partita di RollerCoaster Tycoon 2 salvata +STR_1044 :File di scenario per RollerCoaster Tycoon 2 +STR_1045 :File di paesaggi per RollerCoaster Tycoon 2 +STR_1046 :File di design dei tracciati per RollerCoaster Tycoon 2 +STR_1047 :Salvataggio partita fallito! +STR_1048 :Salvataggio scenario fallito! +STR_1049 :Salvataggio terreno fallito! +STR_1050 :Caricamento fallito...{NEWLINE}Il file contiene dati non validi! +STR_1051 :Supporti invisibili +STR_1052 :Persone invisibili +STR_1053 :{SMALLFONT}{BLACK}Attrazioni nel parco +STR_1054 :{SMALLFONT}{BLACK}Battezza attrazioni +STR_1055 :{SMALLFONT}{BLACK}Battezza persone +STR_1056 :{SMALLFONT}{BLACK}Battezza membri del personale +STR_1057 :Nome dell'attrazione +STR_1058 :Digita il nuovo nome di quest'attrazione:- +STR_1059 :Impossibile ribattezzare l'attrazione... +STR_1060 :Nome dell'attrazione non valido +STR_1061 :Modalità normale +STR_1062 :Modalità a circuito continuo +STR_1063 :Mod. navetta a lancio rovesc. inclinato +STR_1064 :Lancio a motore +STR_1065 :Modalità navetta +STR_1066 :Modalità affitto barche +STR_1067 :Lancio in salita +STR_1068 :Modalità traino rotante +STR_1069 :Modalità stazione-stazione +STR_1070 :Solo un'attrazione a biglietto +STR_1071 :Attrazioni illimitate a biglietto +STR_1072 :Modalità labirinto +STR_1073 :Modalità corsa +STR_1074 :Modalità auto-scontro +STR_1075 :Modalità altalena +STR_1076 :Modalità negozi +STR_1077 :Modalità rotazione +STR_1078 :Rotazione in avanti +STR_1079 :Rotazione all'indietro +STR_1080 :Film: {ENDQUOTES}La vendetta degli aviatori{ENDQUOTES} +STR_1081 :Film 3D: {ENDQUOTES}Code di topo{ENDQUOTES} +STR_1082 :Modalità anelli spaziali +STR_1083 :Modalità principianti +STR_1084 :Lancio a MIL +STR_1085 :Film: {ENDQUOTES}Corse da paura{ENDQUOTES} +STR_1086 :Film 3D: {ENDQUOTES}Via con la tempesta{ENDQUOTES} +STR_1087 :Film 3D: {ENDQUOTES}I predatori dello spazio{ENDQUOTES} +STR_1088 :Modalità intensa +STR_1089 :Modalità berserk +STR_1090 :Modalità casa stregata +STR_1091 :Modalità spettacolo circense +STR_1092 :Lancio in discesa +STR_1093 :Modalità casa distorta +STR_1094 :Modalità caduta libera +STR_1095 :Mod. circuito continuo sezi. a blocchi +STR_1096 :Lancio a motore +STR_1097 :Mod. lancio a motore sez. a blocchi +STR_1098 :In viaggio verso la fine della {POP16}{STRINGID} +STR_1099 :In attesa di passeggeri a {POP16}{STRINGID} +STR_1100 :In attesa di partire {POP16}{STRINGID} +STR_1101 :In partenza {POP16}{STRINGID} +STR_1102 :Velocità di {VELOCITY} +STR_1103 :In arrivo a {POP16}{STRINGID} +STR_1104 :Scarico dei passeggeri a {POP16}{STRINGID} +STR_1105 :Velocità di {VELOCITY} +STR_1106 :In pericolo! +STR_1107 :Incidente! +STR_1108 :Velocità di {VELOCITY} +STR_1109 :In oscillazione +STR_1110 :In rotazione +STR_1111 :In rotazione +STR_1112 :In funzione +STR_1113 :Spettacolo in corso +STR_1114 :In rotazione +STR_1115 :In funzione +STR_1116 :In funzione +STR_1117 :Spettacolo circense in corso +STR_1118 :In funzione +STR_1119 :In attesa di traino con cavo +STR_1120 :Velocità di {VELOCITY} +STR_1121 :In frenata +STR_1122 :In attesa di passeggeri +STR_1123 :In attesa di partire +STR_1124 :In partenza +STR_1125 :In funzione +STR_1126 :In frenata +STR_1127 :Scarico dei passeggeri in corso +STR_1128 :Frenato dai freni di blocco +STR_1129 :Tutti i veicoli degli stessi colori +STR_1130 :Colori diversi per {STRINGID} +STR_1131 :Colori diversi per ogni veicolo +STR_1132 :Veicolo {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Veicolo {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}Scegli il colore principale +STR_1137 :{SMALLFONT}{BLACK}Scegli il colore secondario 1 +STR_1138 :{SMALLFONT}{BLACK}Scegli il colore secondario 2 +STR_1139 :{SMALLFONT}{BLACK}Scegli il colore della struttura di supporto +STR_1140 :{SMALLFONT}{BLACK}Scegli il modello decorativo del veicolo +STR_1141 :{SMALLFONT}{BLACK}Scegli quale veicolo/treno modificare +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1144 :Impossibile costruire/spostare l'entrata di quest'attrazione... +STR_1145 :Impossibile costruire/spostare l'uscita di quest'attrazione... +STR_1146 :Entrata non ancora costruita +STR_1147 :Uscita non ancora costruita +STR_1148 :Un quarto di carico +STR_1149 :Mezzo carico +STR_1150 :3/4 di carico +STR_1151 :Pieno carico +STR_1152 :Qualsiasi carico +STR_1153 :Altezza indicata sul tracciato +STR_1154 :Altezza indicata sul terreno +STR_1155 :Altezza indicata sui sentieri +STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1158 :Impossibile cancellarlo... +STR_1159 :{SMALLFONT}{BLACK}Colloca lo scenario, i giardini e gli altri accessori +STR_1160 :{SMALLFONT}{BLACK}Crea/regola i laghi e gli specchi d'acqua +STR_1161 :Impossibile posizionarlo qui... +STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(Clicca sul pulsante destro per modificare) +STR_1164 :{STRINGID}{NEWLINE}(Clicca sul pulsante destro per cancellare) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :Impossibile abbassare il livello dell'acqua in questo punto... +STR_1167 :Impossibile alzare il livello dell'acqua in questo punto... +STR_1168 :Opzioni +STR_1169 :(Nessuno) +STR_1170 :{STRING} +STR_1171 :{RED}Chiuso - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}Costruisci sentieri e corsie d'attesa +STR_1174 :Un'insegna è d'intralcio +STR_1175 :Impossibile costruirlo su un sentiero in pendenza +STR_1176 :Impossibile costruire un sentiero in questo punto... +STR_1177 :Impossibile cancellare il sentiero da questo punto... +STR_1178 :Pendenza del terreno inadatta +STR_1179 :Un sentiero è d'intralcio +STR_1180 :Impossibile costruirlo sott'acqua!! +STR_1181 :Sentieri +STR_1182 :Tipo +STR_1183 :Direzione +STR_1184 :Pendenza +STR_1185 :{SMALLFONT}{BLACK}Direzione +STR_1186 :{SMALLFONT}{BLACK}Discesa +STR_1187 :{SMALLFONT}{BLACK}Pianeggiante +STR_1188 :{SMALLFONT}{BLACK}Salita +STR_1189 :{SMALLFONT}{BLACK}Costruisci la sezione di sentiero selezionata +STR_1190 :{SMALLFONT}{BLACK}Cancella la sezione di sentiero precedente +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :Chiuso +STR_1195 :Giro di prova +STR_1196 :Aperto +STR_1197 :Guasto +STR_1198 :Schiantato!! +STR_1199 :{COMMA16} persona a bordo +STR_1200 :{COMMA16} persone a bordo +STR_1201 :Niente fila +STR_1202 :1 persona in fila +STR_1203 :{COMMA16} persone in fila +STR_1204 :{COMMA16} minuto in fila d'attesa +STR_1205 :{COMMA16} minuti in fila d'attesa +STR_1206 :{WINDOW_COLOUR_2}Attendi: +STR_1207 :{WINDOW_COLOUR_2}Parti se arriva un altro treno in stazione +STR_1208 :{WINDOW_COLOUR_2}Parti se arriva un'altra barca in stazione +STR_1209 :{SMALLFONT}{BLACK}Scegli se deve attendere dei passeggeri prima di partire +STR_1210 :{SMALLFONT}{BLACK}Scegli se deve partire se arriva un altro veicolo in stazione +STR_1211 :{WINDOW_COLOUR_2}Min. tempo d'attesa: +STR_1212 :{WINDOW_COLOUR_2}Max. tempo d'attesa: +STR_1213 :{SMALLFONT}{BLACK}Scegli il tempo di attesa minimo prima di partire +STR_1214 :{SMALLFONT}{BLACK}Scegli il tempo di attesa massimo prima di partire +STR_1215 :{WINDOW_COLOUR_2}Sincron. con le stazioni adiacenti +STR_1216 :{SMALLFONT}{BLACK}Scegli se sincronizzare la partenza con le stazioni adiacenti (per le 'corse') +STR_1217 :{COMMA16} secondi +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :Solo uscita +STR_1221 :Nessuna entrata +STR_1222 :Nessuna uscita +STR_1223 :{SMALLFONT}{BLACK}Attrazioni di trasporto +STR_1224 :{SMALLFONT}{BLACK}Attrazioni tranquille +STR_1225 :{SMALLFONT}{BLACK}Ottovolanti +STR_1226 :{SMALLFONT}{BLACK}Attrazioni eccitanti +STR_1227 :{SMALLFONT}{BLACK}Attrazioni acquatiche +STR_1228 :{SMALLFONT}{BLACK}Negozi e chioschi +STR_1229 :treno +STR_1230 :treni +STR_1231 :Treno +STR_1232 :Treni +STR_1233 :{COMMA16} treno +STR_1234 :{COMMA16} treni +STR_1235 :Treno {COMMA16} +STR_1236 :barca +STR_1237 :barche +STR_1238 :Barca +STR_1239 :Barche +STR_1240 :{COMMA16} barca +STR_1241 :{COMMA16} barche +STR_1242 :Barca {COMMA16} +STR_1243 :tracciato +STR_1244 :tracciati +STR_1245 :Tracciato +STR_1246 :Tracciati +STR_1247 :{COMMA16} tracciato +STR_1248 :{COMMA16} tracciati +STR_1249 :Tracciato {COMMA16} +STR_1250 :banchina +STR_1251 :banchine +STR_1252 :Banchina +STR_1253 :Banchine +STR_1254 :{COMMA16} banchina +STR_1255 :{COMMA16} banchine +STR_1256 :Banchina {COMMA16} +STR_1257 :stazione +STR_1258 :stazioni +STR_1259 :Stazione +STR_1260 :Stazioni +STR_1261 :{COMMA16} stazione +STR_1262 :{COMMA16} stazioni +STR_1263 :Stazione {COMMA16} +STR_1264 :carrozza +STR_1265 :carrozze +STR_1266 :Carrozza +STR_1267 :Carrozze +STR_1268 :{COMMA16} carrozza +STR_1269 :{COMMA16} carrozze +STR_1270 :Carrozza {COMMA16} +STR_1271 :edificio +STR_1272 :edifici +STR_1273 :Edificio +STR_1274 :Edifici +STR_1275 :{COMMA16} edificio +STR_1276 :{COMMA16} edifici +STR_1277 :Edificio {COMMA16} +STR_1278 :struttura +STR_1279 :strutture +STR_1280 :Struttura +STR_1281 :Strutture +STR_1282 :{COMMA16} struttura +STR_1283 :{COMMA16} strutture +STR_1284 :Struttura {COMMA16} +STR_1285 :nave +STR_1286 :navi +STR_1287 :Nave +STR_1288 :Navi +STR_1289 :{COMMA16} nave +STR_1290 :{COMMA16} navi +STR_1291 :Nave {COMMA16} +STR_1292 :cabina +STR_1293 :cabine +STR_1294 :Cabina +STR_1295 :Cabine +STR_1296 :{COMMA16} cabina +STR_1297 :{COMMA16} cabine +STR_1298 :Cabina {COMMA16} +STR_1299 :ruota +STR_1300 :ruote +STR_1301 :Ruota +STR_1302 :Ruote +STR_1303 :{COMMA16} ruota +STR_1304 :{COMMA16} ruote +STR_1305 :Ruota {COMMA16} +STR_1306 :anello +STR_1307 :anelli +STR_1308 :Anello +STR_1309 :Anelli +STR_1310 :{COMMA16} anello +STR_1311 :{COMMA16} anelli +STR_1312 :Anello {COMMA16} +STR_1313 :giocatore +STR_1314 :giocatori +STR_1315 :Giocatore +STR_1316 :Giocatori +STR_1317 :{COMMA16} giocatore +STR_1318 :{COMMA16} giocatori +STR_1319 :Giocatore {COMMA16} +STR_1320 :buca +STR_1321 :buche +STR_1322 :Buca +STR_1323 :Buche +STR_1324 :{COMMA16}buca +STR_1325 :{COMMA16}buche +STR_1326 :Buca {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}Ruota gli oggetti di 90{DEGREE} +STR_1328 :Prima è necessario livellare il terreno +STR_1329 :{WINDOW_COLOUR_2}Veloc. di lancio: +STR_1330 :{SMALLFONT}{BLACK}Massima velocità alla partenza dalla stazione +STR_1331 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_1332 :{VELOCITY} +STR_1333 :{STRINGID} - {STRINGID}{POP16} +STR_1334 :{STRINGID} - {STRINGID} {COMMA16} +STR_1335 :{STRINGID} - Entrata{POP16}{POP16} +STR_1336 :{STRINGID} - Stazione {POP16}{COMMA16} Entrata +STR_1337 :{STRINGID} - Uscita{POP16}{POP16} +STR_1338 :{STRINGID} - Stazione {POP16}{COMMA16} Uscita +STR_1339 :{BLACK}Risultati non disponibili... +STR_1340 :{WINDOW_COLOUR_2}Max. veloc.: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}Durata corsa: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}Lunghezza corsa: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}Veloc. media: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Max. forza G verticale positiva: {BLACK}{COMMA2DP32}G +STR_1349 :{WINDOW_COLOUR_2}Max. forza G verticale positiva: {OUTLINE}{RED}{COMMA2DP32}G +STR_1350 :{WINDOW_COLOUR_2}Max. forza G verticale negativa: {BLACK}{COMMA2DP32}G +STR_1351 :{WINDOW_COLOUR_2}Max. forza G verticale negativa: {OUTLINE}{RED}{COMMA2DP32}G +STR_1352 :{WINDOW_COLOUR_2}Max. forza G laterale: {BLACK}{COMMA2DP32}G +STR_1353 :{WINDOW_COLOUR_2}Max. forza G laterale: {OUTLINE}{RED}{COMMA2DP32}G +STR_1354 :{WINDOW_COLOUR_2}Picco più alto: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Discese: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Inversioni: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Buchi: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}Assenza di peso in totale: {BLACK}{COMMA2DP32}secondi +STR_1359 :{WINDOW_COLOUR_2}Tempo d'attesa: {BLACK}{COMMA16} minuti. +STR_1360 :{WINDOW_COLOUR_2}Tempo d'attesa: {BLACK}{COMMA16} minuti. +STR_1361 :Impossibile cambiare la velocità... +STR_1362 :Impossibile cambiare la velocità di lancio... +STR_1363 :Troppo in alto per i supporti!! +STR_1364 :I supporti del tracciato non possono essere ulteriormente estesi!! +STR_1365 :Curva in-linea (sx) +STR_1366 :Curva in-linea (dx) +STR_1367 :Mezzo giro della morte +STR_1368 :Mezzo avvitamento (sx) +STR_1369 :Mezzo avvitamento (dx) +STR_1370 :Avvitamento (sx) +STR_1371 :Avvitamento (dx) +STR_1372 :Sal. x traino a lancio +STR_1373 :1/2 giro morte gr. (sx) +STR_1374 :1/2 giro morte gr. (dx) +STR_1375 :Trasferimento in alto +STR_1376 :Trasferimento in basso +STR_1377 :Avvitamento ond. (sx) +STR_1378 :Avvitamento ond. (dx) +STR_1379 :Invertitore (sinistra) +STR_1380 :Invertitore (destra) +STR_1381 :Sal. x traino in curva (sx) +STR_1382 :Sal. x traino in curva (dx) +STR_1383 :1/4 di giro della morte +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}Altre configurazioni del tracciato +STR_1386 :Speciali... +STR_1387 :Impossibile cambiare il tipo di terreno... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}Visuale dell'attrazione +STR_1393 :{SMALLFONT}{BLACK}Dettagli e opzioni del veicolo +STR_1394 :{SMALLFONT}{BLACK}Opzioni operative +STR_1395 :{SMALLFONT}{BLACK}Opzioni della manutenzione +STR_1396 :{SMALLFONT}{BLACK}Opzioni della colorazione +STR_1397 :{SMALLFONT}{BLACK}Opzioni audio +STR_1398 :{SMALLFONT}{BLACK}Dati delle misurazioni e delle prove +STR_1399 :{SMALLFONT}{BLACK}Grafici +STR_1400 :Entrata +STR_1401 :Uscita +STR_1402 :{SMALLFONT}{BLACK}Costruisci o sposta l'entrata dell'attrazione +STR_1403 :{SMALLFONT}{BLACK}Costruisci o sposta l'uscita dell'attrazione +STR_1404 :{SMALLFONT}{BLACK}Ruota di 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Immagine speculare +STR_1406 :{SMALLFONT}{BLACK}Attiva/disattiva lo scenario (se disponibile in fase di progettazione) +STR_1407 :{WINDOW_COLOUR_2}Costruiscilo... +STR_1408 :{WINDOW_COLOUR_2}Costo: {BLACK}{CURRENCY} +STR_1409 :Piatt. d'entrata/uscita +STR_1410 :Torre verticale +STR_1411 :{STRINGID} è d'intralcio +STR_1412 :{WINDOW_COLOUR_3}La registrazione dei dati non è disponibile per questo tipo di attrazione +STR_1413 :{WINDOW_COLOUR_3}La registrazione dati inizierà quando il prossimo {STRINGID} partirà da {STRINGID} +STR_1414 :{SMALLFONT}{BLACK}{DURATION} +STR_1415 :{WINDOW_COLOUR_2}Velocità +STR_1416 :{WINDOW_COLOUR_2}Altitud. +STR_1417 :{WINDOW_COLOUR_2}G vertic. +STR_1418 :{WINDOW_COLOUR_2}G lat. +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}G +STR_1422 :{SMALLFONT}{BLACK}Registraz. dati {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Percorso della corsia d'attesa +STR_1424 :{SMALLFONT}{BLACK}Sentiero +STR_1425 :Sentiero +STR_1426 :Corsia d'attesa +STR_1427 :{WINDOW_COLOUR_2}Clienti: {BLACK}{COMMA32} l'ora +STR_1428 :{WINDOW_COLOUR_2}Prezzo biglietto: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :Gratis +STR_1431 :Sta camminando +STR_1432 :In cammino verso {STRINGID} +STR_1433 :In attesa per {STRINGID} +STR_1434 :Sta annegando +STR_1435 :Su {STRINGID} +STR_1436 :In {STRINGID} +STR_1437 :A {STRINGID} +STR_1438 :Seduto +STR_1439 :(scegli il luogo) +STR_1440 :Sta tagliando l'erba +STR_1441 :Sta scopando per terra +STR_1442 :Sta svuotando i cassonetti +STR_1443 :Sta innaffiando i giardini +STR_1444 :Sta guardando {STRINGID} +STR_1445 :Sta guardano la costruzione di: {STRINGID} +STR_1446 :Sta guardando lo scenario +STR_1447 :Sta lasciando il parco +STR_1448 :Sta osservando la nuova attrazione in costruzione +STR_1449 :{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) +STR_1450 :{INLINE_SPRITE}{MEDIUMFONT}□ +STR_1451 :{STRINGID}{NEWLINE}({STRINGID}) +STR_1452 :Nome del visitatore +STR_1453 :Digita il nome di questo visitatore:- +STR_1454 :Impossibile battezzare il visitatore... +STR_1455 :Il nome del visitatore non è valido +STR_1456 :{WINDOW_COLOUR_2}Denaro speso: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Denaro in tasca: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}Tempo del parco: {BLACK}{REALTIME} +STR_1459 :Stile tracciato +STR_1460 :{SMALLFONT}{BLACK}tracciato aperto a U +STR_1461 :{SMALLFONT}{BLACK}tracciato chiuso a O +STR_1462 :Troppo ripido per il traino in salita +STR_1463 :Visitatori +STR_1464 :Elica in su (piccola) +STR_1465 :Elica in su (grande) +STR_1466 :Elica in giù (piccola) +STR_1467 :Elica in giù (grande) +STR_1468 :Personale +STR_1469 :L'attrazione deve iniziare e terminare con delle stazioni +STR_1470 :La stazione non è abbastanza lunga +STR_1471 :{WINDOW_COLOUR_2}Velocità: +STR_1472 :{SMALLFONT}{BLACK}Velocità di quest'attrazione +STR_1473 :{WINDOW_COLOUR_2}Livello di divertimento: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1474 :{WINDOW_COLOUR_2}Livello di divertimento: {BLACK}Non disponibile +STR_1475 :{WINDOW_COLOUR_2}Livello d'intensità: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Livello d'intensità: {BLACK}Non disponibile +STR_1477 :{WINDOW_COLOUR_2}Livello d'intensità: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Livello di nausea: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Livello di nausea: {BLACK}Non disponibile +STR_1480 :{SMALLFONT}{OPENQUOTES}Non posso permettermi {STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}Ho speso tutti i miei soldi{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}Mi sento male{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}Mi sento molto male{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}Voglio provare qualcosa di più eccitante {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID}sembra troppo intenso per me{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}Non ho ancora finito {STRINGID}{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Solo guardando {STRINGID} mi fa stare male{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}Non pagherò così tanto per andare su {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}Voglio tornare a casa{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} è a buon mercato{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}Ho già: {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}Non posso permettermi: {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}Non ho fame{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}Non ho sete{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}Aiuto!! Sto annegando!!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}Mi sono perso!!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} è stato divertentissimo{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}Sono in fila per {STRINGID} da secoli{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}Sono stanco{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}Ho fame{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}Ho sete{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}Devo andare in bagno{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}Non riesco a trovare: {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}Non pagherò così tanto per usare: {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}Non andrò su {STRINGID} durante un temporale{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}Qui c'è troppa spazzatura in giro{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}Non riesco a trovare l'uscita del parco{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}Voglio scendere da {STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}Voglio uscire da {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}Non andrò su {STRINGID} - Non è sicuro{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}Questo percorso è disgustoso{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}È troppo affollato qui{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}Qui ci sono troppi atti vandalici{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Bello scenario!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}Questo parco è davvero pulito e ordinato{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}Le fontane zampillanti sono fantastiche{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}La musica qui è gradevole{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}Questo palloncino comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}Questo peluche comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}Questa mappa del parco comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}Questa foto-in-corsa comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1522 :{SMALLFONT}{OPENQUOTES}Quest'ombrello comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1523 :{SMALLFONT}{OPENQUOTES}Questa bevanda comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1524 :{SMALLFONT}{OPENQUOTES}Questo panino comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}Queste patatine comprate da {STRINGID} valgono il loro prezzo{ENDQUOTES} +STR_1526 :{SMALLFONT}{OPENQUOTES}Questo gelato comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}Questo zucchero filato comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}Questa pizza comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}Questi pop-corn comprati da {STRINGID} valgono il loro prezzo{ENDQUOTES} +STR_1534 :{SMALLFONT}{OPENQUOTES}Questo hot dog comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1535 :{SMALLFONT}{OPENQUOTES}Questo tentacolo comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1536 :{SMALLFONT}{OPENQUOTES}Questo cappellino comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}Questa mela caramellata comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1538 :{SMALLFONT}{OPENQUOTES}Questa maglietta comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}Questa ciambella comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}Questo caffè comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}Questo pollo fritto comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}Questa limonata comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}Wow!!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}Ho la strana sensazione che qualcuno mi stia osservando{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un palloncino da {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un peluche da {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una mappa del parco da {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una foto-in-corsa da {STRINGID}{ENDQUOTES} +STR_1556 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un ombrello da {STRINGID}{ENDQUOTES} +STR_1557 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una bevanda da {STRINGID}{ENDQUOTES} +STR_1558 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un panino da {STRINGID}{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per delle patatine da {STRINGID}{ENDQUOTES} +STR_1560 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un gelato da {STRINGID}{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per dello zucchero filato da {STRINGID}{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una pizza da {STRINGID}{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per dei pop-corn da {STRINGID}{ENDQUOTES} +STR_1568 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un hot dog da {STRINGID}{ENDQUOTES} +STR_1569 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un tentacolo da {STRINGID}{ENDQUOTES} +STR_1570 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un cappellino da {STRINGID}{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una mela caramellata da {STRINGID}{ENDQUOTES} +STR_1572 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una maglietta da {STRINGID}{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una ciambella da {STRINGID}{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un caffè da {STRINGID}{ENDQUOTES} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per del pollo fritto da {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per della limonata da {STRINGID}{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}Questa foto-in-corsa comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}Questa foto-in-corsa comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}Questa foto-in-corsa comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}Questo biscottino comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}Questa cioccolata calda comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}Questo tè freddo comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}Questa torta a ciambella comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}Questi occhiali da sole comprati da {STRINGID} valgono il loro prezzo{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}Questi spaghetti al ragù comprati da {STRINGID} valgono il loro prezzo{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}Questi spaghetti di riso fritto comprati da {STRINGID} valgono il loro prezzo{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}Questa zuppa di wonton comprata da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}Queste polpette in salsa comprate da {STRINGID} valgono il loro prezzo{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}Questo succo di frutta comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}Questo latte di soia comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}Questo sujongkwa {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}Questo sandwich comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}Questo biscotto comprato da {STRINGID} vale il suo prezzo{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}Queste salsicce comprate da {STRINGID} valgono il loro prezzo{ENDQUOTES} +STR_1605 : +STR_1606 : +STR_1607 : +STR_1608 : +STR_1609 : +STR_1610 : +STR_1611 : +STR_1612 : +STR_1613 : +STR_1614 : +STR_1615 : +STR_1616 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una foto-in-corsa da {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una foto-in-corsa da {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una foto-in-corsa da {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un biscottino da {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una cioccolata calda da {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per del tè freddo da {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per una torta a ciambella da {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un paio di occhiali da sole da {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per degli spaghetti al ragù da {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per degli spaghetti di riso fritto da {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per della zuppa di wonton da {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per delle polpette in salsa da {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un succo di frutta da {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per del latte di soia da {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un sujongkwa da {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un sandwich da {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per un biscotto da {STRINGID}{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}Non pagherò quel prezzo per delle salsicce da {STRINGID}{ENDQUOTES} +STR_1637 : +STR_1638 : +STR_1639 : +STR_1640 : +STR_1641 : +STR_1642 : +STR_1643 : +STR_1644 : +STR_1645 : +STR_1646 : +STR_1647 : +STR_1648 :{SMALLFONT}{OPENQUOTES}Aiuto!! Fatemi scendere!!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}Sto finendo i soldi!!{ENDQUOTES} +STR_1650 :{SMALLFONT}{OPENQUOTES}Wow!! Presto ci sarà una nuova attrazione!!{ENDQUOTES} +STR_1651 :{SMALLFONT}{OPENQUOTES}Bell'attrazione!! Ma mai come la Phoenix...{ENDQUOTES} +STR_1652 :{SMALLFONT}{OPENQUOTES}Che eccitazione - è un'attrazione Intamin!!{ENDQUOTES} +STR_1653 :{SMALLFONT}{OPENQUOTES}...e qui siamo su {STRINGID}!!{ENDQUOTES} +STR_1654 :{WINDOW_COLOUR_2}Pensieri più recenti: +STR_1655 :{SMALLFONT}{BLACK}Costruisci un sentiero sul terreno +STR_1656 :{SMALLFONT}{BLACK}Costruisci un ponte o una galleria +STR_1657 :{WINDOW_COLOUR_2}Attrazione preferita +STR_1658 :{WINDOW_COLOUR_2}intensità: {BLACK}meno di {COMMA16} +STR_1659 :{WINDOW_COLOUR_2}intensità: {BLACK}fra {COMMA16} e {COMMA16} +STR_1660 :{WINDOW_COLOUR_2}intensità: {BLACK}più di {COMMA16} +STR_1661 :{WINDOW_COLOUR_2}Resist. a nausea: {BLACK}{STRINGID} +STR_1662 :{WINDOW_COLOUR_2}Felicità: +STR_1663 :{WINDOW_COLOUR_2}Nausea: +STR_1664 :{WINDOW_COLOUR_2}Energia: +STR_1665 :{WINDOW_COLOUR_2}Fame: +STR_1666 :{WINDOW_COLOUR_2}Sete: +STR_1667 :{WINDOW_COLOUR_2}Toilet: +STR_1668 :{WINDOW_COLOUR_2}Soddisfazione: {BLACK}Ignota +STR_1669 :{WINDOW_COLOUR_2}Soddisfazione: {BLACK}{COMMA16}% +STR_1670 :{WINDOW_COLOUR_2}Totale clienti: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}Profitto totale: {BLACK}{CURRENCY2DP} +STR_1672 :Freni +STR_1673 :Attivatore controllo di rotazione +STR_1674 :Velocità freno +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}Fissa un limite di velocità per i freni +STR_1677 :{WINDOW_COLOUR_2}Popolarità: {BLACK}Ignota +STR_1678 :{WINDOW_COLOUR_2}Popolarità: {BLACK}{COMMA16}% +STR_1679 :Elica in su (sinistra) +STR_1680 :Elica in su (destra) +STR_1681 :Elica in giù (sinistra) +STR_1682 :Elica in giù (destra) +STR_1683 :Dimens. alla base 2 x 2 +STR_1684 :Dimens. alla base 4 x 4 +STR_1685 :Dimens. alla base 2 x 4 +STR_1686 :Dimens. alla base 5 x 1 +STR_1687 :Schizzo d'acqua +STR_1688 :Dimens. alla base 4 x 1 +STR_1689 :Freni di blocco +STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} +STR_1691 :{WINDOW_COLOUR_2} Costo: {BLACK}{CURRENCY} +STR_1692 :{WINDOW_COLOUR_2} Costo: {BLACK}da {CURRENCY} +STR_1693 :{SMALLFONT}{BLACK}Visitatori +STR_1694 :{SMALLFONT}{BLACK}Personale +STR_1695 :{SMALLFONT}{BLACK}Entrate e uscite +STR_1696 :{SMALLFONT}{BLACK}Informazioni per i clienti +STR_1697 :Impossibile collocarli su un'area di attesa +STR_1698 :Possono essere collocati solo su un'area di attesa +STR_1699 :Ci sono troppe persone nella partita +STR_1700 :Assumi un tuttofare +STR_1701 :Assumi un meccanico +STR_1702 :Assumi un vigilante +STR_1703 :Assumi un intrattenitore +STR_1704 :Impossibile assumere dell'altro personale... +STR_1705 :{SMALLFONT}{BLACK}Licenzia questo dipendente +STR_1706 :{SMALLFONT}{BLACK}Sposta questa persona in un altro luogo +STR_1707 :Troppi dipendenti nella partita +STR_1708 :{SMALLFONT}{BLACK}Fissa la zona che questo dipendente deve controllare +STR_1709 :Licenzia il personale +STR_1710 :Sì +STR_1711 :{WINDOW_COLOUR_1}Sei sicuro di voler licenziare{NEWLINE}{STRINGID}? +STR_1712 :{INLINE_SPRITE}÷□ +STR_1713 :{INLINE_SPRITE}ø□ +STR_1714 :{INLINE_SPRITE}ù□ +STR_1715 :{INLINE_SPRITE}ú□ +STR_1716 :Non è un nome valido per il parco +STR_1717 :Impossibile ribattezzare il parco... +STR_1718 :Nome del parco +STR_1719 :Digita il nome del parco:- +STR_1720 :{SMALLFONT}{BLACK}Battezza il parco +STR_1721 :Parco chiuso +STR_1722 :Parco aperto +STR_1723 :Impossibile aprire il parco... +STR_1724 :Impossibile chiudere il parco... +STR_1725 :Impossibile comprare il terreno... +STR_1726 :Il terreno non è in vendita!! +STR_1727 :I diritti di costruzione non sono in vendita!! +STR_1728 :Impossibile comprare i diritti di costruzione qui... +STR_1729 :Questo terreno non è di proprietà del parco!! +STR_1730 :{RED}Chiuso - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :Costruisci +STR_1733 :Modalità +STR_1734 :{WINDOW_COLOUR_2}Numero di giri: +STR_1735 :{SMALLFONT}{BLACK}Numero di giri del circuito +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :Impossibile cambiare il numero di giri... +STR_1739 :Corsa vinta dal visitatore {INT32} +STR_1740 :Corsa vinta da {STRINGID} +STR_1741 :Ancora non è costruito!! +STR_1742 :{WINDOW_COLOUR_2}Max. persone a bordo: +STR_1743 :{SMALLFONT}{BLACK}Numero massimo di persone che possono salire contemporaneamente su quest'attrazione +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :Impossibile modificarlo... +STR_1747 :{WINDOW_COLOUR_2}Tempo limite: +STR_1748 :{SMALLFONT}{BLACK}Limite di tempo per attrazione +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :Impossibile cambiare il limite di tempo per attrazione... +STR_1752 :{SMALLFONT}{BLACK}Mostra la lista completa dei visitatori del parco +STR_1753 :{SMALLFONT}{BLACK}Mostra il riassunto dei visitatori del parco +STR_1754 :{BLACK}{COMMA16} visitatori +STR_1755 :{BLACK}{COMMA16} visitatore +STR_1756 :{WINDOW_COLOUR_2}Prezzo biglietto: +STR_1757 :{WINDOW_COLOUR_2}Affidabilità: {MOVE_X}ÿ{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Modalità costruzione +STR_1759 :{SMALLFONT}{BLACK}Modalità spostamento +STR_1760 :{SMALLFONT}{BLACK}Modalità riempimento +STR_1761 :{SMALLFONT}{BLACK}Costruisci un labirinto in questa direzione +STR_1762 :Cascate +STR_1763 :Rapide +STR_1764 :Salti sui dossi +STR_1765 :Sezione foto-in-corsa +STR_1766 :Piattaforma ribaltabile +STR_1767 :Galleria rotante +STR_1768 :Impossibile cambiare il numero di oscillazioni... +STR_1769 :{WINDOW_COLOUR_2}Numero oscillaz.: +STR_1770 :{SMALLFONT}{BLACK}Numero di oscillazioni complete +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +STR_1773 :Può esserci soltanto una sezione di foto-in-corsa per attrazione +STR_1774 :Può esserci soltanto una salita per il traino con cavo per attrazione +STR_1775 :Off +STR_1776 :On +STR_1777 :{WINDOW_COLOUR_2}Musica +STR_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}þ□ +STR_1780 :{INLINE_SPRITE}ÿ□ +STR_1781 :{INLINE_SPRITE} +STR_1782 :{INLINE_SPRITE}{MOVE_X}□ +STR_1783 :{INLINE_SPRITE}{ADJUST_PALETTE}□ +STR_1784 :{INLINE_SPRITE}□□ +STR_1785 :{INLINE_SPRITE}□□ +STR_1786 :{INLINE_SPRITE}{NEWLINE}□ +STR_1787 :{INLINE_SPRITE}{NEWLINE_SMALLER}□ +STR_1788 :{INLINE_SPRITE}{TINYFONT}□ +STR_1789 :{INLINE_SPRITE}{BIGFONT}□ +STR_1790 :{SMALLFONT}{BLACK}Scegli il colore dell'uniforme per questo tipo di dipendente +STR_1791 :{WINDOW_COLOUR_2}Colore dell'uniforme: +STR_1792 :Sta accorrendo alla chiamata d'emergenza venuta da: {STRINGID} +STR_1793 :Si sta dirigendo verso {STRINGID} per un'ispezione +STR_1794 :Sta riparando {STRINGID} +STR_1795 :Sta rispondendo a una chiamata via radio +STR_1796 :Si è guastato/a e ha bisogno di riparazioni +STR_1797 :Quest'opzione non può essere modificata per quest'attrazione +STR_1798 :Vortice +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :Salvavita +STR_1801 :Freni bloccati (chiusi) +STR_1802 :Freni bloccati (aperti) +STR_1803 :Porta bloccata (chiusa) +STR_1804 :Porta bloccata (aperta) +STR_1805 :Malfunz. del veicolo +STR_1806 :Guasto freni stazione +STR_1807 :Guasto dei comandi +STR_1808 :{WINDOW_COLOUR_2}Ultimo guasto: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Guasto attuale: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Sta trasportando: +STR_1811 :Impossibile costruirlo qui... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :Oggetti vari +STR_1814 :Azioni +STR_1815 :Pensieri +STR_1816 :{SMALLFONT}{BLACK}Scegli il tipo di informazioni da mostrare nella lista dei visitatori +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}Tutti i visitatori +STR_1819 :{WINDOW_COLOUR_2}Tutti i visitatori (riassunto) +STR_1820 :{WINDOW_COLOUR_2}Visitatori {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Pensiero dei visitatori {STRINGID} +STR_1822 :{WINDOW_COLOUR_2}Pensiero dei visitatori su {POP16}{STRINGID} +STR_1823 :{SMALLFONT}{BLACK}Mostra i pensieri dei visitatori relativi a quest'attrazione +STR_1824 :{SMALLFONT}{BLACK}Mostra i visitatori a bordo di quest'attrazione +STR_1825 :{SMALLFONT}{BLACK}Mostra i visitatori in fila d'attesa per quest'attrazione +STR_1826 :Status +STR_1827 :Popolarità +STR_1828 :Soddisfazione +STR_1829 :Profitto +STR_1830 :Lunghezza fila +STR_1831 :Tempo di attesa +STR_1832 :Affidabilità +STR_1833 :Tempi morti +STR_1834 :Attraz. favorita +STR_1835 :Popolarità: Sconosciuta +STR_1836 :Popolarità: {COMMA16}% +STR_1837 :Soddisfazione: Sconosciuta +STR_1838 :Soddisfazione: {COMMA16}% +STR_1839 :Affidabilità: {COMMA16}% +STR_1840 :Tempi morti: {COMMA16}% +STR_1841 :Profitto: {CURRENCY} all'ora +STR_1842 :La preferita da: {COMMA16} visitatore +STR_1843 :La preferita da: {COMMA16} visitatori +STR_1844 :{SMALLFONT}{BLACK}Scegli il tipo di informazione da mostrare nella lista delle attrazioni +STR_1845 :{MONTHYEAR} +STR_1846 :{COMMA16} visitatori +STR_1847 :{INLINE_SPRITE}{OUTLINE}□ +STR_1848 :{INLINE_SPRITE}{SMALLFONT}□ +STR_1849 :{WINDOW_COLOUR_2}Suona la musica +STR_1850 :{SMALLFONT}{BLACK}Scegli quale musica dev'essere suonata in quest'attrazione +STR_1851 :{WINDOW_COLOUR_2}Costo mantenim.: {BLACK}{CURRENCY2DP} l'ora +STR_1852 :{WINDOW_COLOUR_2}Costo mantenim.: {BLACK}Ignoto +STR_1853 :{WINDOW_COLOUR_2}Costruiti: {BLACK}quest'anno +STR_1854 :{WINDOW_COLOUR_2}Costruiti: {BLACK}l'anno scorso +STR_1855 :{WINDOW_COLOUR_2}Costruiti: {BLACK}{COMMA16} anni fa +STR_1856 :{WINDOW_COLOUR_2}Profitto medio per vendita: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Perdita media per vendita: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}Costo: {BLACK}{CURRENCY} al mese +STR_1859 :Tuttofare +STR_1860 :Meccanici +STR_1861 :Vigilanti +STR_1862 :Intrattenitori +STR_1863 :Tuttofare +STR_1864 :Meccanico +STR_1865 :Vigilante +STR_1866 :Intrattenitore +STR_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :Impossibile modificare il numero di rotazioni... +STR_1869 :{WINDOW_COLOUR_2}Numero rotazioni: +STR_1870 :{SMALLFONT}{BLACK}Numero di rotazioni complete +STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1872 :{COMMA16} +STR_1873 :{WINDOW_COLOUR_2}Entrate: {BLACK}{CURRENCY} all'ora +STR_1874 :{WINDOW_COLOUR_2}Profitto: {BLACK}{CURRENCY} all'ora +STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} +STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}û□ +STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}ü□ +STR_1878 :{WINDOW_COLOUR_2}Ispezione: +STR_1879 :Ogni 10 minuti +STR_1880 :Ogni 20 minuti +STR_1881 :Ogni 30 minuti +STR_1882 :Ogni 45 minuti +STR_1883 :Ogni ora +STR_1884 :Ogni 2 ore +STR_1885 :Mai +STR_1886 :Sta effettuando un'ispezione {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Tempo dall'ultima ispezione: {BLACK}{COMMA16} minuti +STR_1888 :{WINDOW_COLOUR_2}Tempo dall'ultima ispezione: {BLACK}più di 4 ore +STR_1889 :{WINDOW_COLOUR_2}Tempi morti: {MOVE_X}ÿ{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Scegli la frequenza con cui un meccanico deve controllare quest'attrazione +STR_1891 :Ancora non ci sono {STRINGID} nel parco!! +STR_1892 :RollerCoaster Tycoon 2 +STR_1893 :Inserisci il tuo CD di RollerCoaster Tycoon 2 nella seguente unità:- +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} venduti/e: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Costruisci una nuova attrazione +STR_1896 :{WINDOW_COLOUR_2}Uscite/entrate +STR_1897 :{WINDOW_COLOUR_2}Costruz. attrazioni +STR_1898 :{WINDOW_COLOUR_2}Costo manten. attraz. +STR_1899 :{WINDOW_COLOUR_2}Acquisto di terreni +STR_1900 :{WINDOW_COLOUR_2}Modifica paesaggio +STR_1901 :{WINDOW_COLOUR_2}Biglietti d'ingresso +STR_1902 :{WINDOW_COLOUR_2}Biglietti attrazioni +STR_1903 :{WINDOW_COLOUR_2}Vendite dei negozi +STR_1904 :{WINDOW_COLOUR_2}Scorte dei negozi +STR_1905 :{WINDOW_COLOUR_2}Vendite di cibo/bevande +STR_1906 :{WINDOW_COLOUR_2}Scorte di cibo/bevande +STR_1907 :{WINDOW_COLOUR_2}Stipendi personale +STR_1908 :{WINDOW_COLOUR_2}Marketing +STR_1909 :{WINDOW_COLOUR_2}Ricerca +STR_1910 :{WINDOW_COLOUR_2}Interessi prestiti +STR_1911 :{BLACK} al {COMMA16}% l'anno +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}Prestito: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :Impossibile chiedere altri prestiti!! +STR_1919 :Fondi insufficienti!! +STR_1920 :Il prestito non può essere restituito!! +STR_1921 :{SMALLFONT}{BLACK}Inizia una nuova partita +STR_1922 :{SMALLFONT}{BLACK}Continua a giocare alla partita salvata +STR_1923 :{SMALLFONT}{BLACK}Mostra l'esercitazione +STR_1924 :{SMALLFONT}{BLACK}Esci +STR_1925 :Impossibile collocare una persona qui... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} si è guastato/a +STR_1928 :{RED}{STRINGID} ha avuto un incidente!! +STR_1929 :{RED}{STRINGID} ancora non è stato riparato{NEWLINE}Guarda dove si trovano i tuoi meccanici e prendi in considerazione l'idea di organizzarli meglio +STR_1930 :{SMALLFONT}{BLACK}Attiva/disattiva le informazioni in tempo reale su questo visitatore - (se l'opzione è attivata, i movimenti del visitatore saranno visualizzati nell'area messaggi) +STR_1931 :{STRINGID} è in fila d'attesa per {STRINGID} +STR_1932 :{STRINGID} si trova su {STRINGID} +STR_1933 :{STRINGID} si trova in {STRINGID} +STR_1934 :{STRINGID} ha lasciato {STRINGID} +STR_1935 :{STRINGID} ha lasciato il parco +STR_1936 :{STRINGID} ha comprato {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Mostra informazioni sull'argomento di questo messaggio +STR_1938 :{SMALLFONT}{BLACK}Mostra la visuale del visitatore +STR_1939 :{SMALLFONT}{BLACK}Mostra la visuale del dipendente +STR_1940 :{SMALLFONT}{BLACK}Mostra la felicità, l'energia, la fame, ecc. di questo visitatore +STR_1941 :{SMALLFONT}{BLACK}Mostra le attrazioni provate da questo visitatore +STR_1942 :{SMALLFONT}{BLACK}Mostra le informazioni finanziarie relative a questo visitatore +STR_1943 :{SMALLFONT}{BLACK}Mostra i pensieri più recenti di questo visitatore +STR_1944 :{SMALLFONT}{BLACK}Mostra l'oggetto che il visitatore sta trasportando +STR_1945 :{SMALLFONT}{BLACK}Mostra le opzioni e gli ordini relativi a questo dipendente +STR_1946 :{SMALLFONT}{BLACK}Scegli il costume di questo intrattenitore +STR_1947 :{SMALLFONT}{BLACK}Mostra le zone sotto il controllo del tipo di dipendente selezionato e individua il dipendente più vicino +STR_1948 :{SMALLFONT}{BLACK}Assumi un altro dipendente del tipo selezionato +STR_1949 :Resoconto finanziario +STR_1950 :Grafico delle finanze +STR_1951 :Grafico del valore del parco +STR_1952 :Grafico dei profitti +STR_1953 :Marketing +STR_1954 :Fondi per la ricerca +STR_1955 :{WINDOW_COLOUR_2}Numero dei circuiti: +STR_1956 :{SMALLFONT}{BLACK}Media dei circuiti del tracciato per attrazione +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :Impossibile modificare il numero dei circuiti... +STR_1960 :{WINDOW_COLOUR_2}Prezzo dei palloncini: +STR_1961 :{WINDOW_COLOUR_2}Prezzo dei peluche: +STR_1962 :{WINDOW_COLOUR_2}Prezzo delle mappe: +STR_1963 :{WINDOW_COLOUR_2}Prezzo delle foto: +STR_1964 :{WINDOW_COLOUR_2}Prezzo degli ombrelli: +STR_1965 :{WINDOW_COLOUR_2}Prezzo delle bevande: +STR_1966 :{WINDOW_COLOUR_2}Prezzo dei panini: +STR_1967 :{WINDOW_COLOUR_2}Prezzo delle patatine: +STR_1968 :{WINDOW_COLOUR_2}Prezzo dei gelati: +STR_1969 :{WINDOW_COLOUR_2}Prezzo dello zucch. fil.: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}Prezzo delle pizze: +STR_1974 :{WINDOW_COLOUR_2} +STR_1975 :{WINDOW_COLOUR_2}Prezzo dei pop-corn: +STR_1976 :{WINDOW_COLOUR_2}Prezzo degli hot dog: +STR_1977 :{WINDOW_COLOUR_2}Prezzo dei tentacoli: +STR_1978 :{WINDOW_COLOUR_2}Prezzo dei cappellini: +STR_1979 :{WINDOW_COLOUR_2}Prezzo delle mele caram.: +STR_1980 :{WINDOW_COLOUR_2}Prezzo delle magliette: +STR_1981 :{WINDOW_COLOUR_2}Prezzo delle ciambelle: +STR_1982 :{WINDOW_COLOUR_2}Prezzo del caffè: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}Prezzo del pollo fritto: +STR_1985 :{WINDOW_COLOUR_2}Prezzo della limonate: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :Palloncino +STR_1989 :Peluche +STR_1990 :Mappa del parco +STR_1991 :Foto-in-corsa +STR_1992 :Ombrello +STR_1993 :Bevanda +STR_1994 :Panino +STR_1995 :Patatine +STR_1996 :Gelato +STR_1997 :Zucchero filato +STR_1998 :Lattina vuota +STR_1999 :Spazzatura +STR_2000 :Confezione per panini vuota +STR_2001 :Pizza +STR_2002 :Buono-sconto +STR_2003 :Pop-corn +STR_2004 :Hot dog +STR_2005 :Tentacolo +STR_2006 :Cappellino +STR_2007 :Mela caramellata +STR_2008 :Maglietta +STR_2009 :Ciambella +STR_2010 :Caffè +STR_2011 :Tazzina vuota +STR_2012 :Pollo fritto +STR_2013 :Limonata +STR_2014 :Scatola vuota +STR_2015 :Bottiglia vuota +STR_2016 :Palloncini +STR_2017 :Peluche +STR_2018 :Mappe del parco +STR_2019 :Foto-in-corsa +STR_2020 :Ombrelli +STR_2021 :Bevande +STR_2022 :Panini +STR_2023 :Patatine +STR_2024 :Gelati +STR_2025 :Zucchero filato +STR_2026 :Lattine vuote +STR_2027 :Spazzatura +STR_2028 :Scatole per panini vuote +STR_2029 :Pizze +STR_2030 :Buoni-sconto +STR_2031 :Pop-corn +STR_2032 :Hot dog +STR_2033 :Tentacoli +STR_2034 :Cappellini +STR_2035 :Mele caramellate +STR_2036 :Magliette +STR_2037 :Ciambelle +STR_2038 :Caffè +STR_2039 :Tazzine vuote +STR_2040 :Polli fritti +STR_2041 :Limonata +STR_2042 :Scatole vuote +STR_2043 :Bottiglie vuote +STR_2044 :un palloncino +STR_2045 :un peluche +STR_2046 :una mappa del parco +STR_2047 :una foto-in-corsa +STR_2048 :un ombrello +STR_2049 :una bevanda +STR_2050 :un panino +STR_2051 :delle patatine +STR_2052 :un gelato +STR_2053 :dello zucchero filato +STR_2054 :una lattina vuota +STR_2055 :della spazzatura +STR_2056 :una scatola per panini vuota +STR_2057 :una pizza +STR_2058 :un buono-sconto +STR_2059 :dei pop-corn +STR_2060 :un hot dog +STR_2061 :un tentacolo +STR_2062 :un cappellino +STR_2063 :una mela caramellata +STR_2064 :una maglietta +STR_2065 :una ciambella +STR_2066 :un caffè +STR_2067 :una tazzina vuota +STR_2068 :del pollo fritto +STR_2069 :della limonata +STR_2070 :una scatola vuota +STR_2071 :una bottiglia vuota +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Palloncino +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Peluche +STR_2074 :Mappa di {STRINGID} +STR_2075 :Foto-in-corsa di {STRINGID} +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Ombrello +STR_2077 :Bevanda +STR_2078 :Panino +STR_2079 :Patatine +STR_2080 :Gelato +STR_2081 :Zucchero filato +STR_2082 :Lattina vuota +STR_2083 :Spazzatura +STR_2084 :Scatola per panini vuota +STR_2085 :Pizza +STR_2086 :Buono-sconto per {STRINGID} +STR_2087 :Pop-corn +STR_2088 :Hot dog +STR_2089 :Tentacolo +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Cappellino +STR_2091 :Mela caramellata +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Maglietta +STR_2093 :Ciambella +STR_2094 :Caffè +STR_2095 :Tazzina vuota +STR_2096 :Pollo fritto +STR_2097 :Limonata +STR_2098 :Scatola vuota +STR_2099 :Bottiglia vuota +STR_2100 :{WINDOW_COLOUR_2}Prezzo delle foto: +STR_2101 :{WINDOW_COLOUR_2}Prezzo delle foto: +STR_2102 :{WINDOW_COLOUR_2}Prezzo delle foto: +STR_2103 :{WINDOW_COLOUR_2}Prezzo dei biscottini: +STR_2104 :{WINDOW_COLOUR_2}Prezzo delle ciocc. calde: +STR_2105 :{WINDOW_COLOUR_2}Prezzo dei tè freddi: +STR_2106 :{WINDOW_COLOUR_2}Prezzo delle torte: +STR_2107 :{WINDOW_COLOUR_2}Prezzo occhiali da sole: +STR_2108 :{WINDOW_COLOUR_2}Prezzo spaghetti al ragù: +STR_2109 :{WINDOW_COLOUR_2}Prezzo spaghetti di riso: +STR_2110 :{WINDOW_COLOUR_2}Prezzo zuppa di wonton: +STR_2111 :{WINDOW_COLOUR_2}Prezzo polpette in salsa: +STR_2112 :{WINDOW_COLOUR_2}Prezzo succhi di frutta: +STR_2113 :{WINDOW_COLOUR_2}Prezzo del latte di soia: +STR_2114 :{WINDOW_COLOUR_2}Prezzo dei sujongkwa: +STR_2115 :{WINDOW_COLOUR_2}Prezzo dei sandwich: +STR_2116 :{WINDOW_COLOUR_2}Prezzo del biscotto: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}Prezzo delle salsicce: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :Prezzo delle foto-in-corsa +STR_2123 :Prezzo delle foto-in-corsa +STR_2124 :Prezzo delle foto-in-corsa +STR_2125 :Biscottino +STR_2126 :Cioccolata calda +STR_2127 :Tè freddo +STR_2128 :Torta a ciambella +STR_2129 :Occhiali da sole +STR_2130 :Spaghetti al ragù +STR_2131 :Spaghetti di riso fritto +STR_2132 :Zuppa di wonton +STR_2133 :Polpette in salsa +STR_2134 :Succo di frutta +STR_2135 :Latte di soia +STR_2136 :Sujongkwa +STR_2137 :Sandwich +STR_2138 :Biscotto +STR_2139 :Scodella vuota +STR_2140 :Confezione per bevande vuota +STR_2141 :Tazza vuota +STR_2142 :Salsicce +STR_2143 :Scodella vuota +STR_2144 :Foto-in.corsa +STR_2145 :Foto-in-corsa +STR_2146 :Foto-in-corsa +STR_2147 :Biscottini +STR_2148 :Cioccolate calde +STR_2149 :Tè freddi +STR_2150 :Torte a ciambella +STR_2151 :Occhiali da sole +STR_2152 :Spaghetti al ragù +STR_2153 :Spaghetti di riso fritto +STR_2154 :Zuppe di wonton +STR_2155 :Polpette in salsa +STR_2156 :Succhi di frutta +STR_2157 :Latte di soia +STR_2158 :Sujongkwa +STR_2159 :Sandwich +STR_2160 :Biscotti +STR_2161 :Scodelle vuote +STR_2162 :Confezioni per bevande vuote +STR_2163 :Tazze vuote +STR_2164 :Salsicce +STR_2165 :Scodelle vuote +STR_2166 :una foto-in-corsa +STR_2167 :una foto-in-corsa +STR_2168 :una foto-in-corsa +STR_2169 :un biscottino +STR_2170 :una cioccolata calda +STR_2171 :un tè freddo +STR_2172 :una torta a ciambella +STR_2173 :un paio di occhiali da sole +STR_2174 :degli spaghetti al ragù +STR_2175 :degli spaghetti di riso fritto +STR_2176 :della zuppa di wonton +STR_2177 :delle polpette in salsa +STR_2178 :un succo di frutta +STR_2179 :del latte di soia +STR_2180 :un sujongkwa +STR_2181 :un sandwich +STR_2182 :un biscotto +STR_2183 :una scodella vuota +STR_2184 :una confezione per bevande vuota +STR_2185 :una tazza vuota +STR_2186 :una salsiccia +STR_2187 :una scodella vuota +STR_2188 :foto-in-corsa di {STRINGID} +STR_2189 :foto-in-corsa di {STRINGID} +STR_2190 :foto-in-corsa di {STRINGID} +STR_2191 :Biscottino +STR_2192 :Cioccolata calda +STR_2193 :Tè freddo +STR_2194 :Torta a ciambella +STR_2195 :Occhiali da sole +STR_2196 :Spaghetti al ragù +STR_2197 :Spaghetti di riso fritto +STR_2198 :Zuppa di wonton +STR_2199 :Polpette in salsa +STR_2200 :Succo di frutta +STR_2201 :Latte di soia +STR_2202 :Sujongkwa +STR_2203 :Sandwich +STR_2204 :Biscotto +STR_2205 :Scodella vuota +STR_2206 :Confezione per bevande vuota +STR_2207 :Tazza vuota +STR_2208 :Salsicce +STR_2209 :Scodella vuota +STR_2210 :{SMALLFONT}{BLACK}Mostra la lista dei tuttofare del parco +STR_2211 :{SMALLFONT}{BLACK}Mostra la lista dei meccanici del parco +STR_2212 :{SMALLFONT}{BLACK}Mostra la lista dei vigilanti del parco +STR_2213 :{SMALLFONT}{BLACK}Mostra la lista degli intrattenitori del parco +STR_2214 :Non è possibile costruire quando il gioco è in pausa!! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2218 :{RED}{STRINGID} sull'attrazione {STRINGID} non ha ancora fatto ritorno presso: {STRINGID} !!{NEWLINE}Controlla se si è bloccato o se è entrato in stallo +STR_2219 :{RED}{COMMA16} persone sono rimaste uccise in un incidente su {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Valutazione del parco: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Valutazione del parco: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}Visitatori nel parco: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}Denaro: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}Denaro: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}Valore del parco: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}Valore della società: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Profitto dello scorso mese derivante da cibo e bevande e {NEWLINE}dalle vendite ai negozi: {BLACK}{CURRENCY} +STR_2229 :Inclinato in alto +STR_2230 :Tracciato verticale +STR_2231 :Frenare in discesa +STR_2232 :Sal. traino con cavo +STR_2233 :{SMALLFONT}{BLACK}Informazioni sul parco +STR_2234 :Messaggi recenti +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :Gennaio +STR_2237 :Febbraio +STR_2238 :Marzo +STR_2239 :Aprile +STR_2240 :Maggio +STR_2241 :Giugno +STR_2242 :Luglio +STR_2243 :Agosto +STR_2244 :Settembre +STR_2245 :Ottobre +STR_2246 :Novembre +STR_2247 :Dicembre +STR_2248 :Impossibile demolire l'attrazione... +STR_2249 :{BABYBLUE}È disponibile una nuova attrazione: {NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}È disponibile un nuovo scenario/tema: {NEWLINE}{STRINGID} +STR_2251 :Può essere costruito solo su un percorso!! +STR_2252 :Può essere costruito solo attraverso un percorso!! +STR_2253 :Attrazioni di trasporto +STR_2254 :Attrazioni tranquille +STR_2255 :Ottovolanti +STR_2256 :Attrazioni eccitanti +STR_2257 :Attrazioni acquatiche +STR_2258 :Negozi e chioschi +STR_2259 :Scenari e temi +STR_2260 :Niente fondi +STR_2261 :Fondi minimi +STR_2262 :Fondi normali +STR_2263 :Fondi massimi +STR_2264 :Ricerca dei fondi +STR_2265 :{WINDOW_COLOUR_2}Costo: {BLACK}{CURRENCY} al mese +STR_2266 :Priorità di ricerca +STR_2267 :Attualmente in fase di sviluppo +STR_2268 :Ultimo progetto sviluppato +STR_2269 :{WINDOW_COLOUR_2}Tipo: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}Progresso: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}Previsione: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Attrazione:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}Scenario/tema:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}Mostra i dettagli di questa invenzione o progetto +STR_2275 :{SMALLFONT}{BLACK}Mostra i fondi e le opzioni per la ricerca e sviluppo +STR_2276 :{SMALLFONT}{BLACK}Mostra lo status della ricerca e sviluppo +STR_2277 :Ignoto +STR_2278 :Attrazione di trasporto +STR_2279 :Attrazione tranquilla +STR_2280 :Ottovolante +STR_2281 :Attrazione eccitante +STR_2282 :Attrazione acquatica +STR_2283 :Negozio/chiosco +STR_2284 :Scenario/tema +STR_2285 :Ricerca iniziale +STR_2286 :In progettazione +STR_2287 :Progetto completato +STR_2288 :Ignoto +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :Scegli uno scenario per una nuova partita +STR_2292 :{WINDOW_COLOUR_2}Attrazioni provate: +STR_2293 :{BLACK} Niente +STR_2294 :{SMALLFONT}{BLACK}Modifica lo stile del terreno alla base +STR_2295 :{SMALLFONT}{BLACK}Modifica gli spigoli verticali del terreno +STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} pagati per entrare +STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16} corsa +STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16} corse +STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16} unità di cibo +STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16}unità di cibo +STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16} bevanda +STR_2302 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16} bevande +STR_2303 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16} souvenir +STR_2304 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spesi in {BLACK}{COMMA16} souvenir +STR_2305 :File dei progetti di tracciato +STR_2306 :Salva il progetto di tracciato +STR_2307 :Seleziona progetto {STRINGID} +STR_2308 :{STRINGID} - Progetti di tracciato +STR_2309 :Installa un nuovo progetto di tracciato +STR_2310 :Costruisci un progetto personalizzato +STR_2311 :{WINDOW_COLOUR_2}Livello di divertimento: {BLACK}{COMMA2DP32} (circa) +STR_2312 :{WINDOW_COLOUR_2}Livello d'intensità: {BLACK}{COMMA2DP32} (circa) +STR_2313 :{WINDOW_COLOUR_2}Livello di nausea: {BLACK}{COMMA2DP32} (circa) +STR_2314 :{WINDOW_COLOUR_2}Lunghezza: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}Costo: {BLACK}circa {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Spazio richiesto: {BLACK}{COMMA16} x {COMMA16} blocchi +STR_2317 :{WINDOW_COLOUR_2}Qualità audio: +STR_2318 :Bassa +STR_2319 :Media +STR_2320 :Alta +STR_2321 :{WINDOW_COLOUR_2}Numero di attrazioni: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Personale: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}Dimensioni del parco: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}Dimensioni del parco: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}Compra del terreno per estendere il parco +STR_2326 :{SMALLFONT}{BLACK}Compra dei diritti di costruzione per permettere la costruzione sopra o sotto il terreno al di fuori del parco +STR_2327 :Opzioni +STR_2328 :{WINDOW_COLOUR_2}Valuta: +STR_2329 :{WINDOW_COLOUR_2}Distanza e velocità: +STR_2330 :{WINDOW_COLOUR_2}Temperatura: +STR_2331 :{WINDOW_COLOUR_2}Indicazioni altezza: +STR_2332 :Unità +STR_2333 :Audio +STR_2334 :Sterline ({POUND}) +STR_2335 :Dollari ($) +STR_2336 :Franchi (F) +STR_2337 :Marchi tedeschi (DM) +STR_2338 :Yen ({YEN}) +STR_2339 :Pesetas (Pts) +STR_2340 :Lire (L) +STR_2341 :Fiorini (fl.) +STR_2342 :Corone (kr) +STR_2343 :Euro ({EURO}) +STR_2344 :Imperiale +STR_2345 :Metrico +STR_2346 :Video +STR_2347 :{RED}{STRINGID} è annegato!! +STR_2348 :{SMALLFONT}{BLACK}Mostra le statistiche di questo dipendente +STR_2349 :{WINDOW_COLOUR_2}Stipendio: {BLACK}{CURRENCY} al mese +STR_2350 :{WINDOW_COLOUR_2}Assunto: {BLACK}{MONTHYEAR} +STR_2351 :{WINDOW_COLOUR_2}Erba tagliata: {BLACK}{COMMA16} +STR_2352 :{WINDOW_COLOUR_2}Giard. innaffiati: {BLACK}{COMMA16} +STR_2353 :{WINDOW_COLOUR_2}Spazz. raccolta: {BLACK}{COMMA16} +STR_2354 :{WINDOW_COLOUR_2}Cass. svuotati: {BLACK}{COMMA16} +STR_2355 :{WINDOW_COLOUR_2}Riparazioni: {BLACK}{COMMA16} +STR_2356 :{WINDOW_COLOUR_2}Ispezioni: {BLACK}{COMMA16} +STR_2357 :Casa +STR_2358 :Unità +STR_2359 :Valori reali +STR_2360 :{WINDOW_COLOUR_2}Risoluzione: +STR_2361 :Addolcimento del paesaggio +STR_2362 :{SMALLFONT}{BLACK}Attiva/disattiva l'addolcimento degli spigoli delle mattonelle del paesaggio +STR_2363 :Griglia sovrapposta al paesaggio +STR_2364 :{SMALLFONT}{BLACK}Attiva/disattiva la griglia sovrapposta al paesaggio +STR_2365 :La banca si è rifiutata di concederti altri prestiti!! +STR_2366 :Celsius ({DEGREE}C) +STR_2367 :Fahrenheit (F) +STR_2368 :Nessuno +STR_2369 :Basso +STR_2370 :Medio +STR_2371 :Alto +STR_2372 :Basso +STR_2373 :Medio +STR_2374 :Alto +STR_2375 :Molto alto +STR_2376 :Estremo +STR_2377 :Super-estremo +STR_2378 :{SMALLFONT}{BLACK}Regola un'area di terreno più piccola +STR_2379 :{SMALLFONT}{BLACK}Regola un'area di terreno più grande +STR_2380 :{SMALLFONT}{BLACK}Regola una superficie d'acqua più piccola +STR_2381 :{SMALLFONT}{BLACK}Regola una superficie d'acqua più grande +STR_2382 :Terreno +STR_2383 :Acqua +STR_2384 :{WINDOW_COLOUR_2}Il tuo obiettivo: +STR_2385 :{BLACK}Nessuno +STR_2386 :{BLACK}Avere almeno {COMMA16} visitatori nel parco entro la fine di {MONTHYEAR}, con una valutazione del parco di almeno 600 +STR_2387 :{BLACK}Far raggiungere al parco un valore di almeno {POP16}{POP16}{CURRENCY} entro la fine di {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR} +STR_2388 :{BLACK}Divertitevii!! +STR_2389 :{BLACK}Costruisci il migliore {STRINGID} che puoi!! +STR_2390 :{BLACK}Avere 10 tipi diversi di ottovolante nel parco, ognuno con un livello di divertimento di almeno 6.00 +STR_2391 :{BLACK}Avere almeno {COMMA16} visitatori nel parco. E non devi mai avere una valutazione del parco inferiore a 700!! +STR_2392 :{BLACK}Incassare mensilmente tramite i biglietti delle attrazioni almeno {POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}Avere 10 tipi diversi di ottovolante nel parco, ognuno della lunghezza minima di {LENGTH} e un livello di divertimento di almeno 7.00 +STR_2394 :{BLACK}Finire di costruire tutti e cinque gli ottovolanti parzialmente costruiti in questo parco, facendo loro raggiungere un livello di divertimento di almeno {POP16}{POP16}{COMMA2DP32} ciascuno +STR_2395 :{BLACK}Restituire il prestito e far raggiungere al parco un valore di almeno {POP16}{POP16}{CURRENCY} +STR_2396 :{BLACK}Incassare mensilmente tramite la vendita di cibo, bevande e oggetti vari almeno {POP16}{POP16}{CURRENCY} +STR_2397 :Nessuno +STR_2398 :Numero di visitatori a una certa data +STR_2399 :Valore del parco a una certa data +STR_2400 :Divertitevi +STR_2401 :Costruisci la migliore attrazione che puoi +STR_2402 :Costruisci 10 ottovolanti +STR_2403 :Numero di visitatori nel parco +STR_2404 :Incasso mensile biglietti attrazioni +STR_2405 :Costruisci 10 ottov. di una certa lunghezza +STR_2406 :Finisci di costruire 5 ottovolanti +STR_2407 :Restit. prestito e parco a un certo valore +STR_2408 :Incasso mensile da cibo/oggetti +STR_2409 :{WINDOW_COLOUR_2}Campagne di marketing all'opera +STR_2410 :{BLACK}Nessuna +STR_2411 :{WINDOW_COLOUR_2}Campagne di marketing disponibili +STR_2412 :{SMALLFONT}{BLACK}Avvia questa campagna di marketing +STR_2413 :{BLACK}({CURRENCY2DP} alla settimana) +STR_2414 :(Non selezionata) +STR_2415 :{WINDOW_COLOUR_2}Attrazione: +STR_2416 :{WINDOW_COLOUR_2}Oggetto: +STR_2417 :{WINDOW_COLOUR_2}Periodo: +STR_2418 :Ingresso gratis a {STRINGID} +STR_2419 :Corsa gratis su {STRINGID} +STR_2420 :Metà prezzo per {STRINGID} +STR_2421 :Gratis: {STRINGID} +STR_2422 :Campagna pubblicitaria per {STRINGID} +STR_2423 :Campagna pubblicitaria per {STRINGID} +STR_2424 :{WINDOW_COLOUR_2}Buoni-sconto con ingresso gratis +STR_2425 :{WINDOW_COLOUR_2}Buoni-sconto con corse gratis specifiche +STR_2426 :{WINDOW_COLOUR_2}Buoni-sconto per ingresso a metà prezzo +STR_2427 :{WINDOW_COLOUR_2}Buoni-sconto per cibo/bevanda gratis +STR_2428 :{WINDOW_COLOUR_2}Campagna pubblicitaria per il parco +STR_2429 :{WINDOW_COLOUR_2}Campagna pubblicitaria per un'attrazione +STR_2430 :{BLACK}Buoni-sconto ingresso gratis a {STRINGID} +STR_2431 :{BLACK}Buoni-sconto corsa gratis su {STRINGID} +STR_2432 :{BLACK}Buoni-sconto metà prezzo per {STRINGID} +STR_2433 :{BLACK}Buoni sconto gratis per: {STRINGID} +STR_2434 :{BLACK}Campagna pubblicitaria per {STRINGID} +STR_2435 :{BLACK}Campagna pubblicitaria per {STRINGID} +STR_2436 :1 sett. +STR_2437 :2 sett. +STR_2438 :3 sett. +STR_2439 :4 sett. +STR_2440 :5 sett. +STR_2441 :6 sett. +STR_2442 :{BLACK}({STRINGID} rimanenti) +STR_2443 :{WINDOW_COLOUR_2}Costo settimanale: {BLACK}{CURRENCY2DP} +STR_2444 :{WINDOW_COLOUR_2}Costo totale: {BLACK}{CURRENCY2DP} +STR_2445 :Comincia la campagna di marketing +STR_2446 :{YELLOW}La campagna di marketing per l'ingresso gratis al parco è terminata +STR_2447 :{YELLOW}La campagna di marketing per le corse gratis su {STRINGID} è terminata +STR_2448 :{YELLOW}La campagna di marketing per l'ingresso a metà prezzo al parco è terminata +STR_2449 :{YELLOW}La campagna di marketing per {STRINGID} gratis è terminata +STR_2450 :{YELLOW}La campagna pubblicitaria per il parco è terminata +STR_2451 :{YELLOW}La campagna pubblicitaria per {STRINGID} è terminata +STR_2452 :{WINDOW_COLOUR_2}Denaro (sottratti i prestiti): {BLACK}{CURRENCY2DP} +STR_2453 :{WINDOW_COLOUR_2}Denaro (sottratti i prestiti): {RED}{CURRENCY2DP} +STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}Mostra i conti economici +STR_2458 :{SMALLFONT}{BLACK}Mostra il grafico di cassa (sottratti i prestiti) nel tempo +STR_2459 :{SMALLFONT}{BLACK}Mostra il grafico del valore del parco nel tempo +STR_2460 :{SMALLFONT}{BLACK}Mostra il grafico del profitto settimanale +STR_2461 :{SMALLFONT}{BLACK}Mostra le campagne di marketing +STR_2462 :{SMALLFONT}{BLACK}Mostra la visuale dell'entrata del parco +STR_2463 :{SMALLFONT}{BLACK}Mostra il grafico della valutazione del parco nel tempo +STR_2464 :{SMALLFONT}{BLACK}Mostra il grafico del numero di visitatori nel tempo +STR_2465 :{SMALLFONT}{BLACK}Mostra il prezzo del biglietto e le informazioni sull'entrata al parco +STR_2466 :{SMALLFONT}{BLACK}Mostra le statistiche del parco +STR_2467 :{SMALLFONT}{BLACK}Mostra gli obiettivi di questa partita +STR_2468 :{SMALLFONT}{BLACK}Mostra i premi che questo parco ha ricevuto recentemente +STR_2469 :{SMALLFONT}{BLACK}Seleziona il livello della ricerca & sviluppo +STR_2470 :{SMALLFONT}{BLACK}Ricerca nuove attrazioni di trasporto +STR_2471 :{SMALLFONT}{BLACK}Ricerca nuove attrazioni tranquille +STR_2472 :{SMALLFONT}{BLACK}Ricerca nuovi ottovolanti +STR_2473 :{SMALLFONT}{BLACK}Ricerca nuove attrazioni eccitanti +STR_2474 :{SMALLFONT}{BLACK}Ricerca nuove attrazioni acquatiche +STR_2475 :{SMALLFONT}{BLACK}Ricerca nuovi negozi e nuovi chioschi +STR_2476 :{SMALLFONT}{BLACK}Ricerca nuovi scenari e nuovi temi +STR_2477 :{SMALLFONT}{BLACK}Seleziona la modalità operativa di quest'attrazione +STR_2478 :{SMALLFONT}{BLACK}Mostra il grafico della velocità nel tempo +STR_2479 :{SMALLFONT}{BLACK}Mostra il grafico dell'altitudine nel tempo +STR_2480 :{SMALLFONT}{BLACK}Mostra il grafico dell'accelerazione verticale nel tempo +STR_2481 :{SMALLFONT}{BLACK}Mostra il grafico dell'accelerazione laterale nel tempo +STR_2482 :{SMALLFONT}{BLACK}Profitto: {CURRENCY} alla settimana, valore del parco: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Profitto settimanale: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Profitto settimanale: {RED}{CURRENCY2DP} +STR_2485 :Comandi +STR_2486 :Generale +STR_2487 :Mostra i {OPENQUOTES}veri{ENDQUOTES} nomi dei visitatori +STR_2488 :{SMALLFONT}{BLACK}Svaria tra i {OPENQUOTES}veri{ENDQUOTES} nomi dei visitatori e i loro numeri +STR_2489 :Tasti rapidi +STR_2490 :Tasti rapidi +STR_2491 :Ripristina +STR_2492 :{SMALLFONT}{BLACK}Riporta le scorciatoie alle impostazioni predefinite +STR_2493 :Chiudi la finestra in cima +STR_2494 :Chiudi tutte le finestre volanti +STR_2495 :Annulla la modalità costruzione +STR_2496 :Metti il gioco in pausa +STR_2497 :Zoom all'indietro +STR_2498 :Zoom in avanti +STR_2499 :Ruota la visuale +STR_2500 :Ruota l'oggetto in costruzione +STR_2501 :Attivatore visuale sotterranea +STR_2502 :Attivatore rimuovi base +STR_2503 :Attivatore rimuovi terr. vert. +STR_2504 :Attivatore attraz. trasparenti +STR_2505 :Attivatore scenario trasparente +STR_2506 :Attivatore supporti invisibili +STR_2507 :Attivatore persone invisibili +STR_2508 :Attivatore indici altezza terreno +STR_2509 :Attivatore indici altezza attraz. +STR_2510 :Attivatore indici altezza percorso +STR_2511 :Regola il terreno +STR_2512 :Regola l'acqua +STR_2513 :Costruisci uno scenario +STR_2514 :Costruisci dei percorsi +STR_2515 :Costruisci una nuova attrazione +STR_2516 :Mostra le informazioni finanziarie +STR_2517 :Mostra informazioni sulla ricerca +STR_2518 :Mostra la lista delle attrazioni +STR_2519 :Mostra informazioni sul parco +STR_2520 :Mostra la lista dei visitatori +STR_2521 :Mostra la lista del personale +STR_2522 :Mostra i messaggi recenti +STR_2523 :Mostra la mappa +STR_2524 :Schermata +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Tasto di ritorno +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Cancella +STR_2538 :Invio +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pausa +STR_2545 :BlocMaiusc +STR_2546 :??? +STR_2547 :??? +STR_2548 :??? +STR_2549 :??? +STR_2550 :??? +STR_2551 :??? +STR_2552 :Escape +STR_2553 :??? +STR_2554 :??? +STR_2555 :??? +STR_2556 :??? +STR_2557 :Barra spaziatrice +STR_2558 :Pagina su +STR_2559 :Pagina giù +STR_2560 :Fine +STR_2561 :Home +STR_2562 :Sinistra +STR_2563 :Su +STR_2564 :Destra +STR_2565 :Giù +STR_2566 :Seleziona +STR_2567 :Stampa +STR_2568 :Esegui +STR_2569 :Istantanea +STR_2570 :Inserisci +STR_2571 :Elimina +STR_2572 :Guida +STR_2573 :0 +STR_2574 :1 +STR_2575 :2 +STR_2576 :3 +STR_2577 :4 +STR_2578 :5 +STR_2579 :6 +STR_2580 :7 +STR_2581 :8 +STR_2582 :9 +STR_2583 :??? +STR_2584 :??? +STR_2585 :??? +STR_2586 :??? +STR_2587 :??? +STR_2588 :??? +STR_2589 :??? +STR_2590 :A +STR_2591 :B +STR_2592 :C +STR_2593 :D +STR_2594 :E +STR_2595 :F +STR_2596 :G +STR_2597 :H +STR_2598 :I +STR_2599 :J +STR_2600 :K +STR_2601 :L +STR_2602 :M +STR_2603 :N +STR_2604 :O +STR_2605 :P +STR_2606 :Q +STR_2607 :R +STR_2608 :S +STR_2609 :T +STR_2610 :U +STR_2611 :V +STR_2612 :W +STR_2613 :X +STR_2614 :Y +STR_2615 :Z +STR_2616 :??? +STR_2617 :??? +STR_2618 :Menu +STR_2619 :??? +STR_2620 :??? +STR_2621 :Tastierino numerico 0 +STR_2622 :Tastierino numerico 1 +STR_2623 :Tastierino numerico 2 +STR_2624 :Tastierino numerico 3 +STR_2625 :Tastierino numerico 4 +STR_2626 :Tastierino numerico 5 +STR_2627 :Tastierino numerico 6 +STR_2628 :Tastierino numerico 7 +STR_2629 :Tastierino numerico 8 +STR_2630 :Tastierino numerico 9 +STR_2631 :Tastierino numerico * +STR_2632 :Tastierino numerico + +STR_2633 :??? +STR_2634 :Tastierino numerico +STR_2635 :Tastierino numerico . +STR_2636 :Tastierino numerico / +STR_2637 :F1 +STR_2638 :F2 +STR_2639 :F3 +STR_2640 :F4 +STR_2641 :F5 +STR_2642 :F6 +STR_2643 :F7 +STR_2644 :F8 +STR_2645 :F9 +STR_2646 :F10 +STR_2647 :F11 +STR_2648 :F12 +STR_2649 :F13 +STR_2650 :F14 +STR_2651 :F15 +STR_2652 :F16 +STR_2653 :F17 +STR_2654 :F18 +STR_2655 :F19 +STR_2656 :F20 +STR_2657 :F21 +STR_2658 :F22 +STR_2659 :F23 +STR_2660 :F24 +STR_2661 :??? +STR_2662 :??? +STR_2663 :??? +STR_2664 :??? +STR_2665 :??? +STR_2666 :??? +STR_2667 :??? +STR_2668 :??? +STR_2669 :BlocNum +STR_2670 :Scorr +STR_2671 :??? +STR_2672 :??? +STR_2673 :??? +STR_2674 :??? +STR_2675 :??? +STR_2676 :??? +STR_2677 :??? +STR_2678 :??? +STR_2679 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees +STR_2697 :??? +STR_2698 :??? +STR_2699 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Never +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. +STR_2711 :; +STR_2712 := +STR_2713 :, +STR_2714 :- +STR_2715 :. +STR_2716 :/ +STR_2717 :' +STR_2718 :(up) +STR_2719 :(new file) +STR_2720 :{UINT16}sec +STR_2721 :{UINT16}secs +STR_2722 :{UINT16}min:{UINT16}sec +STR_2723 :{UINT16}min:{UINT16}secs +STR_2724 :{UINT16}mins:{UINT16}sec +STR_2725 :{UINT16}mins:{UINT16}secs +STR_2726 :{UINT16}min +STR_2727 :{UINT16}mins +STR_2728 :{UINT16}hour:{UINT16}min +STR_2729 :{UINT16}hour:{UINT16}mins +STR_2730 :{UINT16}hours:{UINT16}min +STR_2731 :{UINT16}hours:{UINT16}mins +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, anno {COMMA16} +STR_2737 :{STRINGID} {MONTH}, anno {COMMA16} +STR_2738 :Title screen music: +STR_2739 :None +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat not found +STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat in your RCT2 installation. +STR_2744 :[ +STR_2745 :\ +STR_2746 :] +STR_2747 :# +STR_2748 :Barra +STR_2749 :My new scenario +# New strings used in the cheats window previously these were ??? +STR_2750 :Move all items to top +STR_2751 :Move all items to bottom +STR_2752 :Clear grass +STR_2753 :Mowed grass +STR_2754 :Water plants +STR_2755 :Fix vandalism +STR_2756 :Remove litter +STR_2757 :Force Sun +STR_2758 :Force Thunder +STR_2759 :Zero Clearance +STR_2760 :+5K Money +STR_2761 :Pay For Entrance +STR_2762 :Pay For Rides +STR_2763 :??? +STR_2764 :Happy Guests +STR_2765 :Large Tram +STR_2766 :Win scenario +STR_2767 :Freeze Climate +STR_2768 :Unfreeze Climate +STR_2769 :Open Park +STR_2770 :Close Park +STR_2771 :Slower Gamespeed +STR_2772 :Faster Gamespeed +STR_2773 :Windowed +STR_2774 :Fullscreen +STR_2775 :Fullscreen (desktop) +STR_2776 :Language: +STR_2777 :{MOVE_X}{SMALLFONT}{STRING} +STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +STR_2779 :Viewport #{COMMA16} +STR_2780 :Extra viewport +STR_2781 :{STRINGID}:{MOVE_X}Ã{STRINGID}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :Modifica la scorciatoia +STR_2785 :{WINDOW_COLOUR_2}Premi il nuovo tasto-scorciatoia per : {NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}Clicca sulla descrizione della scorciatoia per selezionare un nuovo tasto +STR_2787 :{WINDOW_COLOUR_2}Valore del parco: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}Congratulazioni!!{NEWLINE}{BLACK}Hai raggiunto il tuo obiettivo: una società del valore di {CURRENCY} !! +STR_2789 :{WINDOW_COLOUR_2}Non hai raggiunto il tuo obiettivo!! +STR_2790 :Digita il tuo nome in classifica +STR_2791 :Digita il tuo nome +STR_2792 :Digita il tuo nome per la classifica degli scenari:- +STR_2793 :{SMALLFONT}(Completato da {STRINGID}) +STR_2794 :{WINDOW_COLOUR_2}Completato da: {BLACK}{STRINGID}{NEWLINE}{WINDOW_COLOUR_2} con una società del valore di: {BLACK}{CURRENCY} +STR_2795 :Ordina +STR_2796 :{SMALLFONT}{BLACK}Ordina la lista delle attrazioni secondo il tipo di informazioni visualizzate +STR_2797 :Scorri lo schermo col puntatore sul bordo +STR_2798 :{SMALLFONT}{BLACK}Seleziona se vuoi che lo schermo scorra quando il puntatore si trova ai bordi dello schermo +STR_2799 :{SMALLFONT}{BLACK}Vedi o modifica le funzioni di comando dei tasti +STR_2800 :{WINDOW_COLOUR_2}Ingressi totali: {BLACK}{COMMA32} +STR_2801 :{WINDOW_COLOUR_2}Entrate dagli ingressi: {BLACK}{CURRENCY2DP} +STR_2802 :Mappa +STR_2803 :{SMALLFONT}{BLACK}Evidenzia questi visitatori sulla mappa +STR_2804 :{SMALLFONT}{BLACK}Evidenzia questi dipendenti sulla mappa +STR_2805 :{SMALLFONT}{BLACK}Mostra la mappa del parco +STR_2806 :{RED}I visitatori si lamentano dello stato indecente dei percorsi del parco{NEWLINE}Guarda dove sono i tuoi tuttofare e prendi in considerazione l'idea di organizzarli meglio +STR_2807 :{RED}I visitatori si lamentano della quantità di cartacce per terra nel parco{NEWLINE}Guarda dove sono i tuoi tuttofare e prendi in considerazione l'idea di organizzarli meglio +STR_2808 :{RED}I visitatori si lamentano degli atti di vandalismo compiuti nel parco{NEWLINE}Guarda dove sono i tuoi vigilanti e prendi in considerazione l'idea di organizzarli meglio +STR_2809 :{RED}I visitatori hanno fame e non riescono a trovare un posto dove comprare del cibo +STR_2810 :{RED}I visitatori hanno sete e non riescono a trovare un posto dove comprare delle bevande +STR_2811 :{RED}I visitatori si lamentano perché non riescono a trovare dei servizi igienici nel parco +STR_2812 :{RED}I visitatori si perdono e rimangono bloccati{NEWLINE}Controlla se è il caso di migliorare la disposizione dei sentieri per aiutare i tuoi visitatori a orientarsi più facilmente +STR_2813 :{RED}Il prezzo del biglietto d'ingresso per il parco è troppo alto!!{NEWLINE}Riduci il prezzo del biglietto o fai in modo di aumentare il valore del parco per attrarre più visitatori +STR_2814 :{WINDOW_COLOUR_2}Premio parco più sporco +STR_2815 :{WINDOW_COLOUR_2}Premio parco più pulito +STR_2816 :{WINDOW_COLOUR_2}Premio parco con il miglior ottovolante +STR_2817 :{WINDOW_COLOUR_2}Premio parco migliore +STR_2818 :{WINDOW_COLOUR_2}Premio parco più bello +STR_2819 :{WINDOW_COLOUR_2}Premio parco peggiore +STR_2820 :{WINDOW_COLOUR_2}Premio parco più sicuro +STR_2821 :{WINDOW_COLOUR_2}Premio miglior personale +STR_2822 :{WINDOW_COLOUR_2}Premio miglior cibo +STR_2823 :{WINDOW_COLOUR_2}Premio peggior cibo +STR_2824 :{WINDOW_COLOUR_2}Premio migliori servizi igienici +STR_2825 :{WINDOW_COLOUR_2}Premio parco più deludente +STR_2826 :{WINDOW_COLOUR_2}Premio migliori attrazioni acquatiche +STR_2827 :{WINDOW_COLOUR_2}Premio migliori attrazioni personalizzate +STR_2828 :{WINDOW_COLOUR_2}Premio colori più sgargianti +STR_2829 :{WINDOW_COLOUR_2}Premio parco più confuso +STR_2830 :{WINDOW_COLOUR_2}Premio migliori attrazioni tranquille +STR_2831 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco più sporco del paese'!! +STR_2832 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco più pulito del paese'!! +STR_2833 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con i migliori ottovolanti'!! +STR_2834 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Miglior parco del paese'!! +STR_2835 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco più bello del paese'!! +STR_2836 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Peggior parco del paese'!! +STR_2837 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco più sicuro del paese'!! +STR_2838 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con il miglior personale'!! +STR_2839 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con il miglior cibo in tutto il paese'!! +STR_2840 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con il peggior cibo in tutto il paese'!! +STR_2841 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con i migliori servizi igienici in tutto il paese'!! +STR_2842 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco più deludente del paese'!! +STR_2843 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con le migliori attrazioni acquatiche del paese'!! +STR_2844 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con le migliori attrazioni personalizzate del paese'!! +STR_2845 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con i colori più sconvolgenti di tutto paese'!! +STR_2846 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco più confuso'!! +STR_2847 :{TOPAZ}Il tuo parco ha ricevuto un premio essendo stato valutato il 'Parco con le migliori attrazioni tranquille del paese'!! +STR_2848 :{WINDOW_COLOUR_2}Nessun premio di recente +STR_2849 :Installazione del nuovo scenario eseguita correttamente +STR_2850 :Installazione del nuovo progetto di tracciato eseguita correttamente +STR_2851 :Scenario già installato +STR_2852 :Progetto di tracciato già installato +STR_2853 :Vietato dalle autorità locali!! +STR_2854 :{RED}I visitatori non riescono a raggiungere l'entrata a {STRINGID} !{NEWLINE}Costruisci un percorso fino all'entrata +STR_2855 :{RED}{STRINGID} non è dotato di un percorso alla sua uscita!!{NEWLINE}Costruisci un percorso che parta dall'uscita dell'attrazione +STR_2856 :{WINDOW_COLOUR_2}Esercitazione +STR_2857 :{WINDOW_COLOUR_2}(Premi un tasto o un pulsante del mouse per assumere il controllo) +STR_2858 :Impossibile avviare la campagna di marketing... +STR_2859 :Al momento è in corso un'altra sezione di RollerCoaster Tycoon 2 +STR_2860 :Riconoscimenti Infogrames... +STR_2861 :{WINDOW_COLOUR_2}Concesso in licenza a Infogrames Interactive +STR_2862 :Riconoscimenti dei brani musicali... +STR_2863 :Riconoscimento dei brani musicali +STR_2864 :{WINDOW_COLOUR_2}Marcia - I Bambini del Reggimento: (Fucik) senza copyright +STR_2865 :{WINDOW_COLOUR_2}Serenata di Heyken: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Compositore ignoto) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Viaggio della sposa: (Tradizionale) +STR_2868 :{WINDOW_COLOUR_2}Racconti dei boschi di Vienna: (Johann Strauss) senza copyright +STR_2869 :{WINDOW_COLOUR_2}Danza slava: (Tradizionale) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Tradizionale) +STR_2871 :{WINDOW_COLOUR_2}Il Biondo Marinaio: (Tradizionale) +STR_2872 :{WINDOW_COLOUR_2}Overture - Il poeta e il Contadino: (Suppe) senza copyright +STR_2873 :{WINDOW_COLOUR_2}Medley di waltzer: (Johann Strauss) senza copyright +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Tradizionale) +STR_2875 :{WINDOW_COLOUR_2}Orginal Recordings (P) 1976 C.J.Mears Organisation, usati per loro concessione +STR_2876 :{WINDOW_COLOUR_2}Musica dei titoli di RollerCoaster Tycoon 2: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2877 :{WINDOW_COLOUR_2}Dodgems Beat: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2878 :{WINDOW_COLOUR_2}Mid Summer's Heat: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2879 :{WINDOW_COLOUR_2}Pharaoh's Tomb: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2880 :{WINDOW_COLOUR_2}Caesar's March: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2881 :{WINDOW_COLOUR_2}Drifting To Heaven: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2882 :{WINDOW_COLOUR_2}Invaders: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2883 :{WINDOW_COLOUR_2}Eternal Toybox: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2884 :{WINDOW_COLOUR_2}Jungle Juice: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2885 :{WINDOW_COLOUR_2}Ninja's Noodles: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2886 :{WINDOW_COLOUR_2}Voyage to Andromeda: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2887 :{WINDOW_COLOUR_2}Brimble's Beat: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2888 :{WINDOW_COLOUR_2}Atlantis: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2889 :{WINDOW_COLOUR_2}Wild West Kid: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2890 :{WINDOW_COLOUR_2}Vampire's Lair: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2891 :{WINDOW_COLOUR_2}Blockbuster: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2892 :{WINDOW_COLOUR_2}Airtime Rock: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2893 :{WINDOW_COLOUR_2}Searchlight Rag: (Scott Joplin/Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2894 :{WINDOW_COLOUR_2}Flight of Fantasy: (Steve Blenkinsopp) copyright {COPYRIGHT} Chris Sawyer +STR_2895 :{WINDOW_COLOUR_2}Big Rock: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2896 :{WINDOW_COLOUR_2}Hypothermia: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2897 :{WINDOW_COLOUR_2}Last Sleigh Ride: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2898 :{WINDOW_COLOUR_2}Pipes of Glencairn: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2899 :{WINDOW_COLOUR_2}Traffic Jam: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2900 :{WINDOW_COLOUR_2} +STR_2901 :{WINDOW_COLOUR_2}(Samples courtesy of Spectrasonics {ENDQUOTES}Liquid Grooves{ENDQUOTES}) +STR_2902 :{WINDOW_COLOUR_2}Toccata: (C.M.Widor, eseguita da Peter James Adcock) registrazione {COPYRIGHT} Chris Sawyer +STR_2903 :{WINDOW_COLOUR_2}Space Rock: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2904 :{WINDOW_COLOUR_2}Manic Mechanic: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2905 :{WINDOW_COLOUR_2}Techno Torture: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2906 :{WINDOW_COLOUR_2}Sweat Dreams: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2907 :{WINDOW_COLOUR_2}What shall we do with the Drunken Sailor: (Anon/Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2908 :{WINDOW_COLOUR_2}Infogrames Interactive +STR_2909 :{WINDOW_COLOUR_2}Produttore senior: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Produttore esecutivo: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Responsabile senior di produzione marketing: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. dello sviluppo del prodotto: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}Responsabile generale: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Direttore del Controllo qualità: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Responsabile della certificazione C.Q.: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Capo della certificazione C.Q.: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Controllo qualità: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Direttore del marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Responsabile dei servizi creativi: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Responsabile dei servizi editoriali e della documentazione: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Progettista grafico: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Redattore pubblicitario: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Ringraziamenti speciali a: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Specialista in ingegneria: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Responsabile dei servizi d'ingegneria: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Capo analista compatibilità: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Analisi compatibilità: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Capo tester: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Tester senior: Matt Pantaleoni +STR_2931 :{WINDOW_COLOUR_2} +STR_2932 :{WINDOW_COLOUR_2} +STR_2933 :{WINDOW_COLOUR_2} +STR_2934 :{WINDOW_COLOUR_2} +STR_2935 :{WINDOW_COLOUR_2} +STR_2936 :{WINDOW_COLOUR_2} +STR_2937 :{WINDOW_COLOUR_2} +STR_2938 :{WINDOW_COLOUR_2} +STR_2939 :{WINDOW_COLOUR_2} +STR_2940 :{WINDOW_COLOUR_2} +STR_2941 :{WINDOW_COLOUR_2} +STR_2942 :{WINDOW_COLOUR_2} +STR_2943 :{WINDOW_COLOUR_2} +STR_2944 :{WINDOW_COLOUR_2} +STR_2945 :{WINDOW_COLOUR_2} +STR_2946 :{WINDOW_COLOUR_2} +STR_2947 :{WINDOW_COLOUR_2} +STR_2948 :{WINDOW_COLOUR_2} +STR_2949 :{WINDOW_COLOUR_2} +STR_2950 :{WINDOW_COLOUR_2} +STR_2951 :{WINDOW_COLOUR_2} +STR_2952 :{WINDOW_COLOUR_2} +STR_2953 :{WINDOW_COLOUR_2} +STR_2954 :{WINDOW_COLOUR_2} +STR_2955 :{WINDOW_COLOUR_2} +STR_2956 :{WINDOW_COLOUR_2} +STR_2957 :{WINDOW_COLOUR_2} +STR_2958 :{WINDOW_COLOUR_2} +STR_2959 :{WINDOW_COLOUR_2} +STR_2960 :{WINDOW_COLOUR_2} +STR_2961 :{WINDOW_COLOUR_2} +STR_2962 :{WINDOW_COLOUR_2} +STR_2963 :{WINDOW_COLOUR_2} +STR_2964 :{WINDOW_COLOUR_2} +STR_2965 :{WINDOW_COLOUR_2} +STR_2966 : +STR_2967 : +STR_2968 : +STR_2969 :L'utilizzo di questo prodotto è soggetto alle condizioni della licenza +STR_2970 :che si trova nel file {OPENQUOTES}ReadMe{ENDQUOTES} del prodotto e nel manuale +STR_2971 :Modello decorativo principale +STR_2972 :Modello decorativo alternativo 1 +STR_2973 :Modello decorativo alternativo 2 +STR_2974 :Modello decorativo alternativo 3 +STR_2975 :{SMALLFONT}{BLACK}Seleziona il modello decorativo da cambiare o da utilizzare +STR_2976 :{SMALLFONT}{BLACK}Dipingi una determinata area di quest'attrazione secondo il modello decorativo selezionato +STR_2977 :Nome del dipendente +STR_2978 :Digita il nome di questo dipendente:- +STR_2979 :Impossibile battezzare il dipendente... +STR_2980 :Troppe insegne nella partita +STR_2981 :{RED}Vietato l'ingresso - - +STR_2982 :Testo dell'insegna +STR_2983 :Digita il testo di questa insegna:- +STR_2984 :Impossibile fissare il testo dell'insegna... +STR_2985 :Insegna +STR_2986 :{SMALLFONT}{BLACK}Modifica il testo dell'insegna +STR_2987 :{SMALLFONT}{BLACK}Imposta quest'insegna come cartello di {OPENQUOTES}Vietato l'ingresso{ENDQUOTES} per i visitatori +STR_2988 :{SMALLFONT}{BLACK}Demolisci questa insegna +STR_2989 :{SMALLFONT}{BLACK}Scegli il colore principale +STR_2990 :{SMALLFONT}{BLACK}Scegli il colore del testo +STR_2991 :Cartello +STR_2992 :Testo del cartello +STR_2993 :Digita il testo del cartello:- +STR_2994 :{SMALLFONT}{BLACK}Modifica il testo del cartello +STR_2995 :{SMALLFONT}{BLACK}Demolisci il cartello +STR_2996 :{BLACK}ABC +STR_2997 :{GREY}ABC +STR_2998 :{WHITE}ABC +STR_2999 :{RED}ABC +STR_3000 :{GREEN}ABC +STR_3001 :{YELLOW}ABC +STR_3002 :{TOPAZ}ABC +STR_3003 :{CELADON}ABC +STR_3004 :{BABYBLUE}ABC +STR_3005 :{PALELAVENDER}ABC +STR_3006 :{PALEGOLD}ABC +STR_3007 :{LIGHTPINK}ABC +STR_3008 :{PEARLAQUA}ABC +STR_3009 :{PALESILVER}ABC +STR_3010 :Impossibile caricare il file... +STR_3011 :Il file contiene dati non validi +STR_3012 :Stile auto da scontro +STR_3013 :Stile organo da fiera +STR_3014 :Stile fanfara romana +STR_3015 :Stile orientale +STR_3016 :Stile marziano +STR_3017 :Stile tamburi nella giungla +STR_3018 :Stile egiziano +STR_3019 :Stile giocattolo +STR_3020 : +STR_3021 :Stile spaziale +STR_3022 :Stile horror +STR_3023 :Stile techno +STR_3024 :Stile tranquillo +STR_3025 :Stile estivo +STR_3026 :Stile acquatico +STR_3027 :Stile far west +STR_3028 :Stile giurassico +STR_3029 :Stile rock +STR_3030 :Stile ragtime +STR_3031 :Stile fantastico +STR_3032 :Stile rock 2 +STR_3033 :Stile ghiacciato +STR_3034 :Stile nevoso +STR_3035 :Musica personalizzata 1 +STR_3036 :Musica personalizzata 2 +STR_3037 :Stile medievale +STR_3038 :Stile urbano +STR_3039 :Stile organo +STR_3040 :Stile meccanico +STR_3041 :Stile moderno +STR_3042 :Stile piratesco +STR_3043 :Stile rock 3 +STR_3044 :Stile dolciumi +STR_3045 :{SMALLFONT}{BLACK}Seleziona uno stile musicale da suonare +STR_3046 :Quest'attrazione non può essere modificata +STR_3047 :Le autorità locali vietano la demolizione o la modifica di quest'attrazione +STR_3048 :Campagne di marketing vietate dalle autorità locali +STR_3049 :Buca da golf A +STR_3050 :Buca da golf B +STR_3051 :Buca da golf C +STR_3052 :Buca da golf D +STR_3053 :Buca da golf E +STR_3054 :Caricamento in corso... +STR_3055 :Bianco +STR_3056 :Traslucido +STR_3057 :{WINDOW_COLOUR_2}Indicatore costruzione: +STR_3058 :Muri di mattoni +STR_3059 :Siepi +STR_3060 :Blocchi di ghiaccio +STR_3061 :Recinti di legno +STR_3062 :{SMALLFONT}{BLACK}Tracciato standard per ottovolante +STR_3063 :{SMALLFONT}{BLACK}Canale d'acqua (tracciato immerso) +STR_3064 :Parchi per principianti +STR_3065 :Parchi impegnativi +STR_3066 :Parchi per esperti +STR_3067 :{OPENQUOTES}Veri{ENDQUOTES} parchi +STR_3068 :Altri parchi +STR_3069 :Sezione superiore +STR_3070 :Pendio a livellare +STR_3071 :{WINDOW_COLOUR_2}Stesso prezzo in tutto il parco +STR_3072 :{SMALLFONT}{BLACK}Scegli se imporre questo prezzo in tutto il parco +STR_3073 :{RED}ATTENZIONE: La valutazione del parco è scesa sotto!!{NEWLINE}Se non farai alzare il punteggio entro 4 settimane, il parco verrà fatto chiudere +STR_3074 :{RED}ATTENZIONE: La valutazione del parco è ancora sotto 700!!{NEWLINE}Hai ancora 3 settimane per rimediare +STR_3075 :{RED}ATTENZIONE: La valutazione del parco è sempre sotto 700!!{NEWLINE}Hai appena 2 settimane per alzare il punteggio, poi il parco verrà fatto chiudere +STR_3076 :{RED}ULTIMO AVVERTIMENTO: La valutazione del parco è rimasta sotto 700!!{NEWLINE}Hai 7 giorni di tempo, poi il parco verrà fatto chiudere se il punteggio non tornerà sopra 700 +STR_3077 :{RED}AVVISO DI CHIUSURA: Hanno fatto chiudere il tuo parco!! +STR_3078 :Entrata semplice +STR_3079 :Entrata di legno +STR_3080 :Entrata a tenda +STR_3081 :Entrata a castello (grigio) +STR_3082 :Entrata a castello (marrone) +STR_3083 :Entrata tropicale +STR_3084 :Entrata a capanna +STR_3085 :Entrata classica/romana +STR_3086 :Entrata astratta +STR_3087 :Entrata nevosa/ghiacciata +STR_3088 :Entrata a pagoda +STR_3089 :Entrata spaziale +STR_3090 :{SMALLFONT}{BLACK}Scegli lo stile dell'entrata, dell'uscita e della stazione +STR_3091 :Non ti è permesso cancellare questa sezione!! +STR_3092 :Non ti è permesso spostare o modificare la stazione di quest'attrazione!! +STR_3093 :{WINDOW_COLOUR_2}Preferito: {BLACK}{STRINGID} +STR_3094 :N/A +STR_3095 :{WINDOW_COLOUR_2}Vel. catena di traino: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}Seleziona la velocità della catena di traino sulla salita +STR_3098 :Impossibile modificare la velocità della catena di traino sulla salita... +STR_3099 :{SMALLFONT}{BLACK}Scegli il colore +STR_3100 :{SMALLFONT}{BLACK}Scegli il secondo colore +STR_3101 :{SMALLFONT}{BLACK}Scegli il terzo colore +STR_3102 :{SMALLFONT}{BLACK}Ridipingi lo scenario colorato sul paesaggio +STR_3103 :Impossibile ridipingerlo... +STR_3104 :{SMALLFONT}{BLACK}Lista delle attrazioni +STR_3105 :{SMALLFONT}{BLACK}Lista dei negozi e chioschi +STR_3106 :{SMALLFONT}{BLACK}Lista degli uffici informazioni e delle altre risorse per i visitatori +STR_3107 :Chiudi +STR_3108 :Prova +STR_3109 :Apri +STR_3110 :{WINDOW_COLOUR_2}Blocca le sezioni: {BLACK}{COMMA16} +STR_3111 :{SMALLFONT}{BLACK}Clicca sul progetto per costruirlo +STR_3112 :{SMALLFONT}{BLACK}Clicca sul progetto per ribattezzarlo o cancellarlo +STR_3113 :Scegli un altro progetto +STR_3114 :{SMALLFONT}{BLACK}Torna alla finestra della scelta dei progetti +STR_3115 :{SMALLFONT}{BLACK}Salva il progetto del tracciato +STR_3116 :{SMALLFONT}{BLACK}Salva il progetto del tracciato (non è possibile finché non viene provata una corsa e così generate delle statistiche) +STR_3117 :{BLACK}Chiamata al meccanico... +STR_3118 :{BLACK}{STRINGID} si sta dirigendo verso l'attrazione +STR_3119 :{BLACK}{STRINGID} sta riparando l'attrazione +STR_3120 :{SMALLFONT}{BLACK}Individua il meccanico disponibile più vicino o il meccanico che sta riparando l'attrazione +STR_3121 :Impossibile individuare il meccanico o tutti i meccanici nei paraggi sono già impegnati +STR_3122 :{WINDOW_COLOUR_2}Attrazione preferita di: {BLACK}{COMMA16} visitatore +STR_3123 :{WINDOW_COLOUR_2}Attrazione preferita di: {BLACK}{COMMA16} visitatori +STR_3124 :Guasto: {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}Fattore di divertimento: {BLACK}+{COMMA16}% +STR_3126 :{WINDOW_COLOUR_2}Fattore d'intensità: {BLACK}+{COMMA16}% +STR_3127 :{WINDOW_COLOUR_2}Fattore di nausea: {BLACK}+{COMMA16}% +STR_3128 :Salva il progetto di tracciato +STR_3129 :Salva il progetto di tracciato con scenario +STR_3130 :Salva +STR_3131 :Annulla +STR_3132 :{BLACK}Clicca sulle parti dello scenario per selezionarle per il salvataggio insieme al progetto di tracciato... +STR_3133 :Impossibile costruirlo su un pendio +STR_3134 :{RED}(Il progetto include uno scenario non disponibile) +STR_3135 :{RED}(Progetto del veicolo non disponibile - le prestazioni dell'attrazione potrebbero risentirne) +STR_3136 :Attenzione: questo progetto verrà costruito con un veicolo alternativo e potrebbe non funzionare come ci si attende. +STR_3137 :Seleziona uno scenario vicino +STR_3138 :Ripristina la selezione +STR_3139 :Il cavo di traino non può funzionare in questa modalità operativa +STR_3140 :La salita per il traino deve iniziare subito dopo la stazione +STR_3141 :Con la salita per il traino non è possibile usare la modalità multi-circuito. +STR_3142 :{WINDOW_COLOUR_2}Capienza: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}Mostra le persone sulla mappa +STR_3144 :{SMALLFONT}{BLACK}Mostra le attrazioni e i negozi sulla mappa +STR_3145 :{SMALLFONT}{BLACK}Scorri {STRINGID} a sinistra +STR_3146 :{SMALLFONT}{BLACK}Scorri {STRINGID} a destra +STR_3147 :{SMALLFONT}{BLACK}Scorri veloce {STRINGID} a sinistra +STR_3148 :{SMALLFONT}{BLACK}Scorri veloce {STRINGID} a destra +STR_3149 :{SMALLFONT}{BLACK}Scorri {STRINGID} a sinistra/destra +STR_3150 :{SMALLFONT}{BLACK}Scorri {STRINGID} in alto +STR_3151 :{SMALLFONT}{BLACK}Scorri {STRINGID} in basso +STR_3152 :{SMALLFONT}{BLACK}Scorri veloce {STRINGID} in alto +STR_3153 :{SMALLFONT}{BLACK}Scorri veloce {STRINGID} in basso +STR_3154 :{SMALLFONT}{BLACK}Scorri {STRINGID} in alto/in basso +STR_3155 : +STR_3156 : +STR_3157 :mappa +STR_3158 :grafico +STR_3159 :lista +STR_3160 :RollerCoaster Tycoon 2: si sta avviando per la prima volta... +STR_3161 :RollerCoaster Tycoon 2: sta cercando i file degli oggetti... +STR_3162 :Impossibile assegnare abbastanza memoria +STR_3163 :Installazione dei nuovi dati: +STR_3164 :{BLACK}{COMMA16} selezionati (massimo {COMMA16}) +STR_3165 : +STR_3166 :{BLACK}(ID: +STR_3167 :{WINDOW_COLOUR_2}Include: {BLACK}{COMMA16} oggetti +STR_3168 :{WINDOW_COLOUR_2}Testo: {BLACK}{STRINGID} +STR_3169 :Non sono stati trovati i dati di quest'oggetto: +STR_3170 :Spazio insufficiente per la grafica +STR_3171 :Sono stati selezionati troppi oggetti di questo tipo +STR_3172 :Quest'oggetto deve prima essere selezionato: +STR_3173 :Quest'oggetto è attualmente in uso +STR_3174 :Quest'oggetto è indispensabile per un altro oggetto +STR_3175 :Quest'oggetto è sempre necessario +STR_3176 :Impossibile selezionare quest'oggetto +STR_3177 :Impossibile deselezionare quest'oggetto +STR_3178 :Dev'essere selezionato almeno un oggetto-percorso +STR_3179 :Dev'essere selezionato almeno un oggetto-attrazione +STR_3180 :Selezione degli oggetti non valida +STR_3181 :Selezione degli oggetti - {STRINGID} +STR_3182 :Dev'essere selezionato il tipo di entrata del parco +STR_3183 :Dev'essere selezionato il tipo di acqua +STR_3184 :Prova veicoli/attrazioni +STR_3185 :Scenario piccolo +STR_3186 :Scenario grande +STR_3187 :Muri/recinti +STR_3188 :Cartelli dei percorsi +STR_3189 :Sentieri +STR_3190 :Percorsi (extra) +STR_3191 :Gruppi di scenari +STR_3192 :Entrata del parco +STR_3193 :Acqua +STR_3194 :Descrizione dello scenario +STR_3195 :Lista delle invenzioni +STR_3196 :{WINDOW_COLOUR_2}Gruppo di ricerca: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}Oggetti già inventati all'avvio della partita +STR_3198 :{WINDOW_COLOUR_2}Oggetti da inventare durante la partita: +STR_3199 :Mischia a caso +STR_3200 :{SMALLFONT}{BLACK}Mischia a caso la lista degli oggetti da inventare durante la partita +STR_3201 :Selezione degli oggetti +STR_3202 :Editor del paesaggio +STR_3203 :Impostazione lista invenzioni +STR_3204 :Selezione delle opzioni +STR_3205 :Selezioni degli obiettivi +STR_3206 :Salva lo scenario +STR_3207 :Progettista di ottovolanti +STR_3208 :Responsabile dei progetti di tracciato +STR_3209 :Torna un passo indietro: +STR_3210 :Vai un passo avanti: +STR_3211 :{WINDOW_COLOUR_2}Dimens. mappa: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :Impossibile rimpicciolire ulteriormente la mappa +STR_3214 :Impossibile ingrandire ulteriormente la mappa +STR_3215 :Troppo vicino al bordo della mappa +STR_3216 :{SMALLFONT}{BLACK}Seleziona il terreno di proprietà del parco ecc. +STR_3217 :Terreno posseduto +STR_3218 :Dir. costruzione acquistati +STR_3219 :Terreno in vendita +STR_3220 :Dir. costruz. in vendita +STR_3221 :{SMALLFONT}{BLACK}Il terreno sarà posseduto dal parco +STR_3222 :{SMALLFONT}{BLACK}I diritti di costruzione potranno essere solo posseduti dal parco +STR_3223 :{SMALLFONT}{BLACK}Il terreno potrà essere comprato dal parco +STR_3224 :{SMALLFONT}{BLACK}I diritti di costruzione potranno essere comprati dal parco +STR_3225 :{SMALLFONT}{BLACK}Attiva/disattiva la costruzione casuale di un gruppo di oggetti intorno alla punto selezionato +STR_3226 :{SMALLFONT}{BLACK}Costruisci l'entrata del parco +STR_3227 :Ci sono troppe entrate per il parco!! +STR_3228 :{SMALLFONT}{BLACK}Fissa le posizioni iniziali delle persone +STR_3229 :I freni di blocco non possono essere usati immediatamente dopo la stazione +STR_3230 :I freni di blocco non possono essere usati l'uno immediatamente dopo l'altro +STR_3231 :I freni di blocco non possono essere usati immediatamente dopo la cima di questa salita di traino +STR_3232 :Opzioni - Finanze +STR_3233 :Opzioni - Visitatori +STR_3234 :Opzioni - Parco +STR_3235 :{SMALLFONT}{BLACK}Mostra le opzioni sulle finanze +STR_3236 :{SMALLFONT}{BLACK}Mostra le opzioni sui visitatori +STR_3237 :{SMALLFONT}{BLACK}Mostra le opzioni sul parco +STR_3238 :Niente denaro +STR_3239 :{SMALLFONT}{BLACK}Rendi questo parco un parco {OPENQUOTES}senza denaro{ENDQUOTES} e senza restrizioni finanziarie +STR_3240 :{WINDOW_COLOUR_2}Denaro iniziale: +STR_3241 :{WINDOW_COLOUR_2}Prestito iniziale: +STR_3242 :{WINDOW_COLOUR_2}Prestito massimo: +STR_3243 :{WINDOW_COLOUR_2}Tasso d'interessi annuo: +STR_3244 :Vieta le campagne di marketing +STR_3245 :{SMALLFONT}{BLACK}Vieta la pubblicità, le campagne promozionali e le altre campagne di marketing +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :Impossibile aumentare ulteriormente il denaro iniziale!! +STR_3249 :Impossibile ridurre ulteriormente il denaro iniziale!! +STR_3250 :Impossibile aumentare ulteriormente il prestito iniziale!! +STR_3251 :Impossibile ridurre ulteriormente il prestito iniziale!! +STR_3252 :Impossibile aumentare ulteriormente il prestito massimo!! +STR_3253 :Impossibile ridurre ulteriormente il prestito massimo!! +STR_3254 :Impossibile aumentare ulteriormente il tasso d'interessi!! +STR_3255 :Impossibile ridurre ulteriormente il tasso d'interessi!! +STR_3256 :Attrazioni meno intense preferite +STR_3257 :{SMALLFONT}{BLACK}Stabilisci se i visitatori in generale dovrebbero preferire solo le attrazioni meno intense +STR_3258 :Attrazioni più intense preferite +STR_3259 :{SMALLFONT}{BLACK}Stabilisci se i visitatori in generale dovrebbero preferire solo attrazioni più intense +STR_3260 :{WINDOW_COLOUR_2}Denaro per visitatore (media): +STR_3261 :{WINDOW_COLOUR_2}Felicità iniziale visitat.: +STR_3262 :{WINDOW_COLOUR_2}Fame iniziale visitat.: +STR_3263 :{WINDOW_COLOUR_2}Sete iniziale visitat.: +STR_3264 :Impossibile aumentarlo ulteriormente!! +STR_3265 :Impossibile ridurlo ulteriormente!! +STR_3266 :{SMALLFONT}{BLACK}Stabilisci il prezzo dell'ingresso e delle attrazioni +STR_3267 :Vieta la rimozione degli alberi +STR_3268 :{SMALLFONT}{BLACK}Vieta la rimozione degli alberi alti +STR_3269 :Vieta la modifica del paesaggio +STR_3270 :{SMALLFONT}{BLACK}Vieta qualsiasi modifica al paesaggio +STR_3271 :Vieta costruzioni alte +STR_3272 :{SMALLFONT}{BLACK}Vieta tutte le costruzioni alte +STR_3273 :Valutazione del parco a un livello di difficoltà più elevato +STR_3274 :{SMALLFONT}{BLACK}Rendi la valutazione del parco più impegnativa +STR_3275 :Generazione dei visitatori a un livello di difficoltà più elevato +STR_3276 :{SMALLFONT}{BLACK}Rendi più difficile attrarre visitatori al parco +STR_3277 :{WINDOW_COLOUR_2}Costo del terreno: +STR_3278 :{WINDOW_COLOUR_2}Costo dei diritti di costruzione: +STR_3279 :Ingresso gratis/paga l'attraz. +STR_3280 :Paga l'ingresso/attraz. gratis +STR_3281 :{WINDOW_COLOUR_2}Prezzo d'ingresso: +STR_3282 :{SMALLFONT}{BLACK}Seleziona gli obiettivi e il nome del parco +STR_3283 :{SMALLFONT}{BLACK}Seleziona le attrazioni da proteggere +STR_3284 :Selezione degli obiettivi +STR_3285 :Attrazioni protette +STR_3286 :{SMALLFONT}{BLACK}Seleziona l'obiettivo di questo scenario +STR_3287 :{WINDOW_COLOUR_2}Obiettivo: +STR_3288 :{SMALLFONT}{BLACK}Scegli il clima +STR_3289 :{WINDOW_COLOUR_2}Clima: +STR_3290 :Freddo e umido +STR_3291 :Temperato +STR_3292 :Caldo e secco +STR_3293 :Freddo +STR_3294 :Modifica... +STR_3295 :{SMALLFONT}{BLACK}Ribattezza il parco +STR_3296 :{SMALLFONT}{BLACK}Modifica il nome dello scenario +STR_3297 :{SMALLFONT}{BLACK}Modifica le informazioni sul parco/scenario +STR_3298 :{WINDOW_COLOUR_2}Nome parco: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}Inform. sul parco/scenario: +STR_3300 :{WINDOW_COLOUR_2}Nome scenario: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Data-obiettivo: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}Numero visitatori: +STR_3304 :{WINDOW_COLOUR_2}Valore parco: +STR_3305 :{WINDOW_COLOUR_2}Entrate mensili: +STR_3306 :{WINDOW_COLOUR_2}Profitto mensile: +STR_3307 :{WINDOW_COLOUR_2}Lunghezza minima: +STR_3308 :{WINDOW_COLOUR_2}Liv. divertimento: +STR_3309 :{WINDOW_COLOUR_2}{COMMA16} +STR_3310 :{WINDOW_COLOUR_2}{LENGTH} +STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} +STR_3312 :{WINDOW_COLOUR_2}Attrazioni sotto ordine di protezione: +STR_3313 :Nome scenario +STR_3314 :Digita il nome dello scenario:- +STR_3315 :Informazioni sul parco/scenario +STR_3316 :Scrivi una descrizione dello scenario:- +STR_3317 :Ancora nessuna informazione +STR_3318 :{SMALLFONT}{BLACK}Scegli in quale gruppo sarà incluso questo scenario +STR_3319 :{WINDOW_COLOUR_2}Gruppo scenari: +STR_3320 :Impossibile salvare il file di scenario... +STR_3321 :Installazione dei nuovi oggetti eseguita correttamente +STR_3322 :{WINDOW_COLOUR_2}Obiettivo: {BLACK}{STRINGID} +STR_3323 :Dati sull'oggetto mancanti, ID: +STR_3324 :È necessaria l'espansione: +STR_3325 :È necessaria un'espansione +STR_3326 :{WINDOW_COLOUR_2}(nessuna immagine) +STR_3327 :Posizioni iniziali delle persone non fissate +STR_3328 :Impossibile passare alla fase successiva dell'editor... +STR_3329 :L'entrata del parco non è stata ancora costruita +STR_3330 :Il parco deve possedere del terreno +STR_3331 :Il percorso dall'entrata del parco al bordo della mappa non è completo o è troppo complesso. Dev'essere di larghezza singola con il minor numero possibile di collegamenti e curve +STR_3332 :L'entrata del parco è oriantata nel senso sbagliato o non ha un percorso che conduce al bordo della mappa +STR_3333 :Esporta oggetti di plug-in insieme alle partite salvate +STR_3334 :{SMALLFONT}{BLACK}Scegli se salvare gli eventuali dati necessari degli oggetti di plug-in (dati non forniti con il prodotto principale) all'interno dei file di scenario o delle partite salvate, permettendone così l'accesso anche a chi non possiede questi dati addizionali +STR_3335 :Progettista degli ottovolanti - Seleziona il tipo di veicoli e attrazione +STR_3336 :Responsabile dei progetti di tracciato - Seleziona il tipo di attrazione +STR_3337 :Parco Six Flags +STR_3338 :{BLACK}Disposizione personalizzata +STR_3339 :{BLACK}{COMMA16} progetto disponibile o progetto personalizzato +STR_3340 :{BLACK}{COMMA16} progetti disponibili o disposizioni personalizzate +STR_3341 :{SMALLFONT}{BLACK}Strumenti di gioco +STR_3342 :Editor degli scenari +STR_3343 :Converti la partita salvata in uno scenario +STR_3344 :Strumento di progettazione degli ottovolanti +STR_3345 :Strumento di gestione dei progetti di tracciato +STR_3346 :Impossibile salvare il progetto di tracciato... +STR_3347 :L{GREEN}attrazione è troppo grande, contiene troppi elementi o lo scenario è sparso su un'area troppo vasta +STR_3348 :Ribattezza +STR_3349 :Cancella +STR_3350 :Battezza il progetto di tracciato +STR_3351 :Digita il nome di questo progetto di tracciato:- +STR_3352 :Impossibile ribattezzare il progetto di tracciato... +STR_3353 :Il nuovo nome contiene dei caratteri non validi +STR_3354 :Esiste già un altro file con quel nome, o il file è protetto dalla scrittura +STR_3355 :Il file è protetto dalla scrittura o è chiuso all'accesso +STR_3356 :Cancella il file +STR_3357 :{WINDOW_COLOUR_2}Sei sicuro di voler cancellare permanentemente {STRINGID} ? +STR_3358 :Impossibile cancellare il progetto di tracciato... +STR_3359 :{BLACK}Non ci sono progetti di tracciato di questi tipo +STR_3360 :Attenzione! +STR_3361 :Troppi progetti di tracciato di questo tipo - qualcuno non verrà elencato. +STR_3362 :Mixaggio software del buffer forzato +STR_3363 :{SMALLFONT}{BLACK}Seleziona questa opzione per migliorare le prestazioni se quando viene avviato il sonoro il gioco rallenta leggermente o si sentono dei disturbi +STR_3364 :Avanzato +STR_3365 :{SMALLFONT}{BLACK}Permetti la selezione di oggetti singoli di uno scenario in aggiunta ai gruppi di scenario +STR_3366 :{BLACK}= Attrazione +STR_3367 :{BLACK}= Chiosco cibo +STR_3368 :{BLACK}= Chiosco bevande +STR_3369 :{BLACK}= Chiosco souvenir +STR_3370 :{BLACK}= Chiosco inform. +STR_3371 :{BLACK}= Pronto soccorso +STR_3372 :{BLACK}= A.T.M. +STR_3373 :{BLACK}= Servizi igien. +STR_3374 :Attenzione: hai selezionato troppi oggetti!! +STR_3375 :Non è stato possibile selezionare tutti gli oggetti di questo gruppo di scenari +STR_3376 :Installa un nuovo progetto di tracciato... +STR_3377 :{SMALLFONT}{BLACK}Installa un nuovo file di progetti di tracciato +STR_3378 :Installa +STR_3379 :Annulla +STR_3380 :Impossibile installare questo progetto di tracciato... +STR_3381 :Il file non è compatibile o contiene dati non validi +STR_3382 :Tentativo di copia del file fallito +STR_3383 :Scegli un nuovo nome per il progetto di tracciato +STR_3384 :Questo nome è già usato da un progetto di tracciato esistente - scegli un altro nome per questo progetto: +STR_3385 :Esercitazione per principianti +STR_3386 :Esercitazione per le attrazioni personalizzate +STR_3387 :Esercitazione per la costruzione di ottovolanti +STR_3388 :Impossibile passare alla modalità selezionata: DirectX ha causato un errore +STR_3389 :Impossibile selezionare l'oggetto aggiuntivo dello scenario... +STR_3390 :Troppi oggetti selezionati +STR_3391 :{SMALLFONT}{BLACK}Ecco il nostro parco - andiamo a dare un'occhiata in giro... +STR_3392 :{SMALLFONT}{BLACK}Tenere premuto il pulsante DESTRO del mouse e muovere il mouse stesso è il modo più veloce per spostare la visuale... +STR_3393 :{SMALLFONT}{BLACK}Per allargare la prospettiva, puoi zoomare in avanti tramite l'icona in cima allo schermo... +STR_3394 :{SMALLFONT}{BLACK}Puoi anche ruotare la visuale di 90{DEGREE} alla volta... +STR_3395 :{SMALLFONT}{BLACK}È difficile costruire qualcosa con questa scala, per cui torniamo a zoomare in dentro... +STR_3396 :{SMALLFONT}{BLACK}Costruiamo un'attrazione semplice per avviare il parco... +STR_3397 :{SMALLFONT}{BLACK}L'immagine fantasma bianca mostra la posizione in cui verrà costruita la nuova attrazione. Muoveremo il puntatore per scegliere la posizione e poi cliccheremo per costruire... +STR_3398 :{SMALLFONT}{BLACK}Le attrazioni devono avere un'entrata e un'uscita. Muoveremo il puntatore su un riquadro adiacente all'attrazione e poi cliccheremo per costruire prima l'entrata e poi l'uscita... +STR_3399 :{SMALLFONT}{BLACK}Dobbiamo costruire dei sentieri per permettere ai visitatori di raggiungere la nostra nuova attrazione... +STR_3400 :{SMALLFONT}{BLACK}Per il percorso che porta all'entrata dell'attrazione useremo un percorso speciale: la 'corsia d'attesa'... +STR_3401 :{SMALLFONT}{BLACK}Per il percorso d'uscita basterà un percorso 'normale'... +STR_3402 :{SMALLFONT}{BLACK}Bene, ora apriamo l'attrazione! Per aprire l'attrazione clicchiamo sull'icona a bandiera nella finestra dell'attrazione e selezioniamo 'apri'... +STR_3403 :{SMALLFONT}{BLACK}Ma dove sono i visitatori? +STR_3404 :{SMALLFONT}{BLACK}Oh - il parco è ancora chiuso! Beh, apriamolo... +STR_3405 :{SMALLFONT}{BLACK}Mentre aspettiamo i nostri primi visitatori, costruiamo degli scenari... +STR_3406 :{SMALLFONT}{BLACK}Ecco il nostro parco vuoto. Ora andremo a costruire un'attrazione personalizzata molto semplice... +STR_3407 :{SMALLFONT}{BLACK}Prima dobbiamo selezionare la posizione di partenza... +STR_3408 :{SMALLFONT}{BLACK}La sezione di tracciato che abbiamo appena costruito è la 'piattaforma di una stazione', che permette ai visitatori di salire e scendere dall'attrazione... +STR_3409 :{SMALLFONT}{BLACK}Ora estenderemo un po' la piattaforma aggiungendo un altro paio di sezioni... +STR_3410 :{SMALLFONT}{BLACK}Le icone in cima alla finestra di costruzione ti permettono di scegliere le varie parti del tracciato da aggiungere... +STR_3411 :{SMALLFONT}{BLACK}Ora selezioneremo una curva a sinistra... +STR_3412 :{SMALLFONT}{BLACK}La curva non è stata ancora costruita, ma una sua immagine fantasma bianca ci mostra dove verrà collocata. Per costruirla, clicchiamo sulla grande icona 'costruiscilo'... +STR_3413 :{SMALLFONT}{BLACK}Ora vogliamo costruire una parte di tracciato diritta, per cui clicchiamo sull'icona del tracciato diritto... +STR_3414 :{SMALLFONT}{BLACK}Ora che il circuito è completo, dobbiamo costruire l'entrata e l'uscita dell'attrazione... +STR_3415 :{SMALLFONT}{BLACK}Ora proviamo a vedere se l'attrazione funziona... +STR_3416 :{SMALLFONT}{BLACK}Mentre viene effettuata la prova, costruiremo la corsia d'attesa e il percorso d'uscita... +STR_3417 :{SMALLFONT}{BLACK}OK - apriamo il parco e l'attrazione... +STR_3418 :{SMALLFONT}{BLACK}La nostra nuova attrazione non è molto eccitante - forse dovremmo aggiungere qualche scenario in più? +STR_3419 :{SMALLFONT}{BLACK}Per costruire uno scenario sopra un altro scenario o a mezz'aria, tieni premuto SHIFT e sposta il mouse per selezionare l'altezza... +STR_3420 :{SMALLFONT}{BLACK}Alcuni tipi di scenario possono essere ridipinti dopo che li si è costruiti... +STR_3421 :{SMALLFONT}{BLACK}Aggiungiamo della musica all'attrazione... +STR_3422 :{SMALLFONT}{BLACK}Costruiamo un ottovolante!! +STR_3423 :{SMALLFONT}{BLACK}Ci sono parecchi ottovolanti già progettati, ma ora noi ne cotruiremo uno personalizzato... +STR_3424 :{SMALLFONT}{BLACK}Ecco costruita la piattaforma della stazione. Ora dobbiamo costruire una salita di traino... +STR_3425 :{SMALLFONT}{BLACK}I treni degli ottovolanti non hanno un motore, per cui è necessaria una 'catena da traino' per far salire il treno sulla prima salita... +STR_3426 :{SMALLFONT}{BLACK}Ecco completata la salita di traino - e ora pensiamo alla prima discesa... +STR_3427 :{SMALLFONT}{BLACK}Quelle curve sono una cattiva idea - i passeggeri verranno sbalzati via dalla forza G laterale durante la corsa sfrenata del treno... +STR_3428 :{SMALLFONT}{BLACK}Per migliorare l'attrazione occorre inclinare le curve - così i passeggeri verranno schiacciati verso i propri sedili invece di essere sbalzati fuori... +STR_3429 :{SMALLFONT}{BLACK}No - non funzionerà! Guarda gli indici dell'altezza - la seconda salita è più alta di quella di traino... +STR_3430 :{SMALLFONT}{BLACK}Per far sì che il treno possa arrivare fino alla fine, ogni salita dev'essere leggermente più bassa di quella precedente... +STR_3431 :{SMALLFONT}{BLACK}Così va meglio - ora il nostro treno dovrebbe farcela! Ora proviamo con un tracciato più contorto... +STR_3432 :{SMALLFONT}{BLACK}Dovremo rallentare la corsa del treno prima dell'ultima curva e della stazione, per cui aggiungiamo dei freni... +STR_3433 :{SMALLFONT}{BLACK}E infine aggiungeremo i 'freni di blocco', che permettono a due treni di operare nel circuito con maggior sicurezza... +STR_3434 :{SMALLFONT}{BLACK}Ora proviamo l'attrazione e vediamo se funziona!! +STR_3435 :{SMALLFONT}{BLACK}Fantastico - ha funzionato! Ora aggiungiamo i sentieri e facciamo accomodare i visitatori sul nostro nuovo ottovolante... +STR_3436 :{SMALLFONT}{BLACK}Mentre aspettiamo i nostri primi passeggeri, potremmo personalizzare un po' l'attrazione... +STR_3437 :{SMALLFONT}{BLACK}Elimina gli alberi, i muri e i piccoli oggetti di scenario dal terreno +STR_3438 :Impossibile rimuovere tutto lo scenario da qui... +STR_3439 :Elimina scen. +STR_3440 :Pagina 1 +STR_3441 :Pagina 2 +STR_3442 :Pagina 3 +STR_3443 :Pagina 4 +STR_3444 :Pagina 5 +STR_3445 :Imposta l'area da pattugliare +STR_3446 :Annulla l'area da pattugliare + +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renew rides +STR_5124 :No Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +#Thousands separator +STR_5151 :. +#Decimal separator +STR_5152 :, +STR_5153 :Colour schemes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpaths +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear diff --git a/data/language/polish.txt b/data/language/polish.txt index 34260d3a26..ca5ed8af91 100644 --- a/data/language/polish.txt +++ b/data/language/polish.txt @@ -983,28 +983,30 @@ STR_0973 :OK STR_0974 :Atrakcje STR_0975 :Sklepy STR_0976 :Toalety i Punkty Informacyjne -# ------------------------------------------ Polish end -STR_0977 :New Transport Rides -STR_0978 :New Gentle Rides -STR_0979 :New Roller Coasters -STR_0980 :New Thrill Rides -STR_0981 :New Water Rides -STR_0982 :New Shops & Stalls -STR_0983 :Research & Development +STR_0977 :Nowa atrakcja transportowa +STR_0978 :Nowa łagodna atrakcja +STR_0979 :Nowa kolejka górska +STR_0980 :Nowa intensywna atrakcja +STR_0981 :Nowa wodna atrakcja +STR_0982 :Nowy sklep lub stoisko +STR_0983 :Badania i rozwój STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} STR_0986 :{BLACK}{CURRENCY2DP} +# ------------------------------------------ Polish end STR_0987 :Too many rides/attractions STR_0988 :Can't create new ride/attraction... STR_0989 :{STRINGID} STR_0990 :{SMALLFONT}{BLACK}Construction STR_0991 :Station platform -STR_0992 :{SMALLFONT}{BLACK}Demolish entire ride/attraction -STR_0993 :Demolish ride/attraction -STR_0994 :Demolish -STR_0995 :{WINDOW_COLOUR_1}Are you sure you want to completely demolish {STRINGID}? -STR_0996 :Overall view -STR_0997 :{SMALLFONT}{BLACK}View selection +# ------------------------------------------ Polish start +STR_0992 :{SMALLFONT}{BLACK}Zniszcz całą atrakcję +STR_0993 :Zniszcz atrakcję +STR_0994 :Zniszcz +STR_0995 :{WINDOW_COLOUR_1}Jesteś pewien, że chcesz zniszczyć {STRINGID}? +STR_0996 :Widok ogólny +STR_0997 :{SMALLFONT}{BLACK}Wybór widoku +# ------------------------------------------ Polish end STR_0998 :No more stations allowed on this ride STR_0999 :Requires a station platform STR_1000 :Track is not a complete circuit @@ -1015,13 +1017,15 @@ STR_1004 :Can't close {POP16}{POP16}{POP16}{STRINGID}... STR_1005 :Can't start construction on {POP16}{POP16}{POP16}{STRINGID}... STR_1006 :Must be closed first STR_1007 :Unable to create enough vehicles -STR_1008 :{SMALLFONT}{BLACK}Open, close, or test ride/attraction -STR_1009 :{SMALLFONT}{BLACK}Open or close all rides/attractions -STR_1010 :{SMALLFONT}{BLACK}Open or close park -STR_1011 :Close all -STR_1012 :Open all -STR_1013 :Close park -STR_1014 :Open park +# ------------------------------------------ Polish start +STR_1008 :{SMALLFONT}{BLACK}Otwórz, zamknij lub testuj atrakcję +STR_1009 :{SMALLFONT}{BLACK}Otwórz / zamknij wszystkie atrakcje +STR_1010 :{SMALLFONT}{BLACK}Otwórz / zamknij park +STR_1011 :Zamknij wszystkie +STR_1012 :Otwórz wszystkie +STR_1013 :Zamknij park +STR_1014 :Otwórz park +# ------------------------------------------ Polish end STR_1015 :Unable to operate with more than one station platform in this mode STR_1016 :Unable to operate with less than two stations in this mode STR_1017 :Can't change operating mode... @@ -1043,27 +1047,29 @@ STR_1032 :Can only build this on water! STR_1033 :Can only build this above ground! STR_1034 :Can only build this on land! STR_1035 :Local authority won't allow construction above tree-height! -STR_1036 :Load Game -STR_1037 :Load Landscape -STR_1038 :Convert saved game to scenario -STR_1039 :Install new track design -STR_1040 :Save Game -STR_1041 :Save Scenario -STR_1042 :Save Landscape -STR_1043 :RollerCoaster Tycoon 2 Saved Game -STR_1044 :RollerCoaster Tycoon 2 Scenario File -STR_1045 :RollerCoaster Tycoon 2 Landscape File -STR_1046 :RollerCoaster Tycoon 2 Track Design File -STR_1047 :Game save failed! -STR_1048 :Scenario save failed! -STR_1049 :Landscape save failed! -STR_1050 :Failed to load...{NEWLINE}File contains invalid data! -STR_1051 :Invisible Supports -STR_1052 :Invisible People -STR_1053 :{SMALLFONT}{BLACK}Rides/attractions in park -STR_1054 :{SMALLFONT}{BLACK}Name ride/attraction -STR_1055 :{SMALLFONT}{BLACK}Name person -STR_1056 :{SMALLFONT}{BLACK}Name staff member +# ------------------------------------------ Polish start +STR_1036 :Wczytaj grę +STR_1037 :Wczytaj krajobraz +STR_1038 :Przekonwertuj zapis gry do scenariusza +STR_1039 :Dodaj nowy projekt trasy +STR_1040 :Zapisz grę +STR_1041 :Zapisz scenariusz +STR_1042 :Zapisz krajobraz +STR_1043 :Zapis gry RollerCoaster Tycoon 2 +STR_1044 :Scenariusz RollerCoaster Tycoon 2 +STR_1045 :Krajobrazu RollerCoaster Tycoon 2 +STR_1046 :Projekt trasy RollerCoaster Tycoon 2 +STR_1047 :Zapis gry nieudany! +STR_1048 :Zapis scenariusza nieudany! +STR_1049 :Zapis krajobrazu nieudany! +STR_1050 :Nie udało się wczytać...{NEWLINE}Plik zawiera błędne dane! +STR_1051 :Przezroczyste wsporniki +STR_1052 :Przezroczyści ludzie +STR_1053 :{SMALLFONT}{BLACK}Atrakcje w parku +STR_1054 :{SMALLFONT}{BLACK}Nazwij atrakcję +STR_1055 :{SMALLFONT}{BLACK}Nazwij osobę +STR_1056 :{SMALLFONT}{BLACK}Nazwij pracownika +# ------------------------------------------ Polish end STR_1057 :Ride/attraction name STR_1058 :Enter new name for this ride/attraction: STR_1059 :Can't rename ride/attraction... @@ -1071,7 +1077,7 @@ STR_1060 :Invalid ride/attraction name STR_1061 :Normal mode STR_1062 :Continuous circuit mode STR_1063 :Reverse-Incline launched shuttle mode -STR_1064 :Powered launch +STR_1064 :Powered launch (passing station) STR_1065 :Shuttle mode STR_1066 :Boat hire mode STR_1067 :Upward launch @@ -1103,7 +1109,7 @@ STR_1092 :Downward launch STR_1093 :Crooked house mode STR_1094 :Freefall drop mode STR_1095 :Continuous circuit block sectioned mode -STR_1096 :Powered launch +STR_1096 :Powered launch (without passing station) STR_1097 :Powered launch block sectioned mode STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} @@ -1155,25 +1161,25 @@ STR_1144 :Can't build/move entrance for this ride/attraction... STR_1145 :Can't build/move exit for this ride/attraction... STR_1146 :Entrance not yet built STR_1147 :Exit not yet built -STR_1148 :Quarter load -STR_1149 :Half load -STR_1150 :Three-quarter load -STR_1151 :Full load -STR_1152 :Any load -STR_1153 :Height Marks on Ride Tracks -STR_1154 :Height Marks on Land -STR_1155 :Height Marks on Paths +# ------------------------------------------ Polish start +STR_1148 :25% zapełnienia +STR_1149 :50% zapełnienia +STR_1150 :70% zapełnienia +STR_1151 :100% zapełnienia +STR_1152 :dowolne zapełnienie +STR_1153 :Znaczniki wysokości torów +STR_1154 :Znaczniki wysokości terenu +STR_1155 :Znaczniki wysokości chodników STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} -STR_1158 :Can't remove this... -STR_1159 :{SMALLFONT}{BLACK}Place scenery, gardens, and other accessories -STR_1160 :{SMALLFONT}{BLACK}Create/adjust lakes & water -STR_1161 :Can't position this here... +STR_1158 :Nie można tego usunąć... +STR_1159 :{SMALLFONT}{BLACK}Buduj scenerię, ogrody i inne akcesoria +STR_1160 :{SMALLFONT}{BLACK}Twórz i zmieniaj obszary wodne +STR_1161 :Nie można tego tu umieścić... STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} -STR_1163 :{STRINGID}{NEWLINE}(Right-Click to Modify) -STR_1164 :{STRINGID}{NEWLINE}(Right-Click to Remove) +STR_1163 :{STRINGID}{NEWLINE}(Kliknij PPM by zmodyfikować) +STR_1164 :{STRINGID}{NEWLINE}(Kliknij PPM by usunąć) STR_1165 :{STRINGID} - {STRINGID} {COMMA16} -# ------------------------------------------ Polish start STR_1166 :Nie można tu obniżyć poziomu wody... STR_1167 :Nie można tu podnieść poziomu wody... STR_1168 :Opcje @@ -1214,21 +1220,21 @@ STR_1202 :1 osoba w kolejce STR_1203 :{COMMA16} osób w kolejce STR_1204 :{COMMA16} minuta czekania STR_1205 :{COMMA16} minut czekania -# ------------------------------------------ Polish end -STR_1206 :{WINDOW_COLOUR_2}Wait for: -STR_1207 :{WINDOW_COLOUR_2}Leave if another train arrives at station -STR_1208 :{WINDOW_COLOUR_2}Leave if another boat arrives at station -STR_1209 :{SMALLFONT}{BLACK}Select whether should wait for passengers before departing -STR_1210 :{SMALLFONT}{BLACK}Select whether should leave if another vehicle arrives at the same station -STR_1211 :{WINDOW_COLOUR_2}Minimum waiting time: -STR_1212 :{WINDOW_COLOUR_2}Maximum waiting time: -STR_1213 :{SMALLFONT}{BLACK}Select minimum length of time to wait before departing -STR_1214 :{SMALLFONT}{BLACK}Select maximum length of time to wait before departing -STR_1215 :{WINDOW_COLOUR_2}Synchronize with adjacent stations -STR_1216 :{SMALLFONT}{BLACK}Select whether to synchronize departure with all adjacent stations (for 'racing') -STR_1217 :{COMMA16} seconds +STR_1206 :{WINDOW_COLOUR_2}Czekaj na: +STR_1207 :{WINDOW_COLOUR_2}Wyrusz, gdy inna kolejka trafi na tą samą stację +STR_1208 :{WINDOW_COLOUR_2}Wyrusz, gdy inna łódka trafi na tą samą stację +STR_1209 :{SMALLFONT}{BLACK}Ustal, czy pojazdy powinny czekać na pasażerów przed wyruszeniem ze stacji +STR_1210 :{SMALLFONT}{BLACK}Ustal, czy pojazdy powinny wyruszać ze stacj gdy tylko inny pojazd dotrze do tej samej stacji +STR_1211 :{WINDOW_COLOUR_2}Minimalny czas oczekiwania: +STR_1212 :{WINDOW_COLOUR_2}Maksymalny czas oczekiwania: +STR_1213 :{SMALLFONT}{BLACK}Wybierz minimalny czas oczekiwania na stacji przed wyruszeniem +STR_1214 :{SMALLFONT}{BLACK}Wybierz maksymalny czas oczekiwania na stacji przed wyruszeniem +STR_1215 :{WINDOW_COLOUR_2}Synchronizuj z sąsiadującymi stacjami +STR_1216 :{SMALLFONT}{BLACK}Wybierz, czy kolejki mają synchronizować start z innymi stacjami (dla 'wyścigów') +STR_1217 :{COMMA16} sekund STR_1218 :{BLACK}{SMALLUP} STR_1219 :{BLACK}{SMALLDOWN} +# ------------------------------------------ Polish end STR_1220 :Exit only STR_1221 :No entrance STR_1222 :No exit @@ -1666,20 +1672,22 @@ STR_1650 :{SMALLFONT}{OPENQUOTES}Wow! A new ride being built!{ENDQUOTES} STR_1651 :{SMALLFONT}{OPENQUOTES}Nice ride! But not as good as the Phoenix...{ENDQUOTES} STR_1652 :{SMALLFONT}{OPENQUOTES}I'm so excited - It's an Intamin ride!{ENDQUOTES} STR_1653 :{SMALLFONT}{OPENQUOTES}...and here we are on {STRINGID}!{ENDQUOTES} -STR_1654 :{WINDOW_COLOUR_2}Recent thoughts: -STR_1655 :{SMALLFONT}{BLACK}Construct footpath on land -STR_1656 :{SMALLFONT}{BLACK}Construct bridge or tunnel footpath -STR_1657 :{WINDOW_COLOUR_2}Preferred ride -STR_1658 :{WINDOW_COLOUR_2}intensity: {BLACK}less than {COMMA16} -STR_1659 :{WINDOW_COLOUR_2}intensity: {BLACK}between {COMMA16} and {COMMA16} -STR_1660 :{WINDOW_COLOUR_2}intensity: {BLACK}more than {COMMA16} -STR_1661 :{WINDOW_COLOUR_2}Nausea tolerance: {BLACK}{STRINGID} -STR_1662 :{WINDOW_COLOUR_2}Happiness: -STR_1663 :{WINDOW_COLOUR_2}Nausea: -STR_1664 :{WINDOW_COLOUR_2}Energy: -STR_1665 :{WINDOW_COLOUR_2}Hunger: -STR_1666 :{WINDOW_COLOUR_2}Thirst: -STR_1667 :{WINDOW_COLOUR_2}Bathroom: +# ------------------------------------------ Polish start +STR_1654 :{WINDOW_COLOUR_2}Ostatnie myśli: +STR_1655 :{SMALLFONT}{BLACK}Buduj ścieżki na ziemi +STR_1656 :{SMALLFONT}{BLACK}Buduj ścieżki w powietrzu lub pod ziemią +STR_1657 :{WINDOW_COLOUR_2}Preferowana +STR_1658 :{WINDOW_COLOUR_2}intensywność: {BLACK}poniżej {COMMA16} +STR_1659 :{WINDOW_COLOUR_2}intensywność: {BLACK}między {COMMA16} a {COMMA16} +STR_1660 :{WINDOW_COLOUR_2}intensywność: {BLACK}powyżej {COMMA16} +STR_1661 :{WINDOW_COLOUR_2}Odporność na mdłości: {BLACK}{STRINGID} +STR_1662 :{WINDOW_COLOUR_2}Szczęście: +STR_1663 :{WINDOW_COLOUR_2}Mdłości: +STR_1664 :{WINDOW_COLOUR_2}Energia: +STR_1665 :{WINDOW_COLOUR_2}Głód: +STR_1666 :{WINDOW_COLOUR_2}Pragnienie: +STR_1667 :{WINDOW_COLOUR_2}Pęcherz: +# ------------------------------------------ Polish end STR_1668 :{WINDOW_COLOUR_2}Satisfaction: {BLACK}Unknown STR_1669 :{WINDOW_COLOUR_2}Satisfaction: {BLACK}{COMMA16}% STR_1670 :{WINDOW_COLOUR_2}Total customers: {BLACK}{COMMA32} @@ -1791,7 +1799,7 @@ STR_1773 :Only one on-ride photo section allowed per ride STR_1774 :Only one cable lift hill allowed per ride STR_1775 :Off STR_1776 :On -STR_1777 :{WINDOW_COLOUR_2}Music: +STR_1777 :{WINDOW_COLOUR_2}Music STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigre costume @@ -1840,48 +1848,51 @@ STR_1822 :{WINDOW_COLOUR_2}Guests thinking about {POP16}{STRINGID} STR_1823 :{SMALLFONT}{BLACK}Show guests' thoughts about this ride/attraction STR_1824 :{SMALLFONT}{BLACK}Show guests on this ride/attraction STR_1825 :{SMALLFONT}{BLACK}Show guests queuing for this ride/attraction -STR_1826 :Status -STR_1827 :Popularity -STR_1828 :Satisfaction -STR_1829 :Profit -STR_1830 :Queue length -STR_1831 :Queue time -STR_1832 :Reliability -STR_1833 :Down-time -STR_1834 :Guests favorite -STR_1835 :Popularity: Unknown -STR_1836 :Popularity: {COMMA16}% -STR_1837 :Satisfaction: Unknown -STR_1838 :Satisfaction: {COMMA16}% -STR_1839 :Reliability: {COMMA16}% -STR_1840 :Down-time: {COMMA16}% -STR_1841 :Profit: {CURRENCY} per hour -STR_1842 :Favorite of: {COMMA16} guest -STR_1843 :Favorite of: {COMMA16} guests -STR_1844 :{SMALLFONT}{BLACK}Select information type to show in ride/attraction list +# ------------------------------------------ Polish start +STR_1826 :Stan +STR_1827 :Popularność +STR_1828 :Satysfakcja +STR_1829 :Zysk +STR_1830 :Długość kolejki +STR_1831 :Czas w kolejce +STR_1832 :Niezawodność +STR_1833 :Przestoje +STR_1834 :Ulubieniec gości +STR_1835 :Popularność: Nieznana +STR_1836 :Popularność: {COMMA16}% +STR_1837 :Satysfakcja: Nieznana +STR_1838 :Satysfakcja: {COMMA16}% +STR_1839 :Niezawodność: {COMMA16}% +STR_1840 :Przestoje w pracy: {COMMA16}% +STR_1841 :Zysk: {CURRENCY} per hour +STR_1842 :Ulubiony dla: {COMMA16} gościa +STR_1843 :Ulubiony dla: {COMMA16} gości +STR_1844 :{SMALLFONT}{BLACK}Wybierz rodzaj informacji do pokazania STR_1845 :{MONTHYEAR} -STR_1846 :{COMMA16} guests -STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} guests -STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} guests -STR_1849 :{WINDOW_COLOUR_2}Play music -STR_1850 :{SMALLFONT}{BLACK}Select whether music should be played for this ride -STR_1851 :{WINDOW_COLOUR_2}Running cost: {BLACK}{CURRENCY2DP} per hour -STR_1852 :{WINDOW_COLOUR_2}Running cost: {BLACK}Unknown -STR_1853 :{WINDOW_COLOUR_2}Built: {BLACK}This Year -STR_1854 :{WINDOW_COLOUR_2}Built: {BLACK}Last Year -STR_1855 :{WINDOW_COLOUR_2}Built: {BLACK}{COMMA16} Years Ago -STR_1856 :{WINDOW_COLOUR_2}Profit per item sold: {BLACK}{CURRENCY2DP} -STR_1857 :{WINDOW_COLOUR_2}Loss per item sold: {BLACK}{CURRENCY2DP} -STR_1858 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} per month -STR_1859 :Handymen -STR_1860 :Mechanics -STR_1861 :Security Guards -STR_1862 :Entertainers -STR_1863 :Handyman -STR_1864 :Mechanic -STR_1865 :Security Guard -STR_1866 :Entertainer +STR_1846 :{COMMA16} gości +STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} gości +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} gości +STR_1849 :{WINDOW_COLOUR_2}Graj muzykę +STR_1850 :{SMALLFONT}{BLACK}Wybierz, czy w tej atrakcji może grać muzyka +STR_1851 :{WINDOW_COLOUR_2}Koszty utrzymania: {BLACK}{CURRENCY2DP} na godzinę +STR_1852 :{WINDOW_COLOUR_2}Koszty utrzymania: {BLACK}Nieznane +STR_1853 :{WINDOW_COLOUR_2}Zbudowany: {BLACK}W tym roku +STR_1854 :{WINDOW_COLOUR_2}Zbudowany: {BLACK}W zeszłym roku +STR_1855 :{WINDOW_COLOUR_2}Zbudowany: {BLACK}{COMMA16} lat temu +STR_1856 :{WINDOW_COLOUR_2}Zysk na sztuce: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Strata na sztuce: {BLACK}{CURRENCY2DP} +# could be "pensja" but I'm not sure if it's used outside of staff window +STR_1858 :{WINDOW_COLOUR_2}Koszt: {BLACK}{CURRENCY} miesięcznie +STR_1859 :dozorcy +STR_1860 :mechanicy +STR_1861 :strażnicy +STR_1862 :klauni +STR_1863 :dozorca +STR_1864 :mechanik +STR_1865 :strażnik +STR_1866 :klaun STR_1867 :{BLACK}{COMMA16} {STRINGID} +# ------------------------------------------ Polish end STR_1868 :Can't change number of rotations... STR_1869 :{WINDOW_COLOUR_2}Number of rotations: STR_1870 :{SMALLFONT}{BLACK}Number of complete rotations @@ -2273,7 +2284,7 @@ STR_2252 :Można budować tylko w poprzek chodników! STR_2253 :Transport STR_2254 :Łagodne atrakcje STR_2255 :Kolejki górskie -STR_2256 :Mocne atrakcje +STR_2256 :Intensywne atrakcje STR_2257 :Wodne atrakcje STR_2258 :Sklepy i stoiska STR_2259 :Scenerie i dekoracje @@ -2298,7 +2309,7 @@ STR_2277 :Nieznany STR_2278 :Transport STR_2279 :Łagodne atrakcje STR_2280 :Kolejki górskie -STR_2281 :Mocne atrakcje +STR_2281 :Intensywne atrakcje STR_2282 :Wodne atrakcje STR_2283 :Sklepy i stoiska STR_2284 :Scenerie i dekoracje @@ -2309,20 +2320,22 @@ STR_2288 :Nieznane STR_2289 :{STRINGID} {STRINGID} STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} STR_2291 :Wybierz scenariusz dla nowej gry +STR_2292 :{WINDOW_COLOUR_2}Odwiedzone atrakcje: +STR_2293 :{BLACK} Nic # ------------------------------------------ Polish end -STR_2292 :{WINDOW_COLOUR_2}Rides been on: -STR_2293 :{BLACK} Nothing STR_2294 :{SMALLFONT}{BLACK}Change base land style STR_2295 :{SMALLFONT}{BLACK}Change vertical edges of land -STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} paid to enter park -STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} ride -STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} rides -STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} item of food -STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} items of food -STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} drink -STR_2302 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} drinks -STR_2303 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} souvenir -STR_2304 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} spent on {BLACK}{COMMA16} souvenirs +# ------------------------------------------ Polish start +STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na wejście do parku +STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} atrakcji +STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} atrakcjach +STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} posiłku +STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} posiłkach +STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} napoju +STR_2302 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} napojach +STR_2303 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} pamiątce +STR_2304 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} wydane na {BLACK}{COMMA16} pamiątkach +# ------------------------------------------ Polish end STR_2305 :Track design files STR_2306 :Save track design STR_2307 :Select {STRINGID} design @@ -2360,25 +2373,23 @@ STR_2337 :Marki (DM) STR_2338 :Jeny ({YEN}) STR_2339 :Pesety (Pts) STR_2340 :Liry (L) -STR_2341 :Guldeny (Dfl.) +STR_2341 :Guldeny (fl.) STR_2342 :Korony (kr) STR_2343 :Euro ({EURO}) STR_2344 :Imperialne STR_2345 :Metryczne STR_2346 :Grafika STR_2347 :{RED}{STRINGID} utonął! -# ------------------------------------------ Polish end -STR_2348 :{SMALLFONT}{BLACK}Show statistics for this staff member -STR_2349 :{WINDOW_COLOUR_2}Wages: {BLACK}{CURRENCY} per month -STR_2350 :{WINDOW_COLOUR_2}Employed: {BLACK}{MONTHYEAR} -STR_2351 :{WINDOW_COLOUR_2}Lawns mown: {BLACK}{COMMA16} -STR_2352 :{WINDOW_COLOUR_2}Gardens watered: {BLACK}{COMMA16} -STR_2353 :{WINDOW_COLOUR_2}Litter swept: {BLACK}{COMMA16} -STR_2354 :{WINDOW_COLOUR_2}Bins emptied: {BLACK}{COMMA16} -STR_2355 :{WINDOW_COLOUR_2}Rides fixed: {BLACK}{COMMA16} -STR_2356 :{WINDOW_COLOUR_2}Rides inspected: {BLACK}{COMMA16} -STR_2357 :House -# ------------------------------------------ Polish start +STR_2348 :{SMALLFONT}{BLACK}Pokaż statystyki tego pracownika +STR_2349 :{WINDOW_COLOUR_2}Pensja: {BLACK}{CURRENCY} miesięcznie +STR_2350 :{WINDOW_COLOUR_2}Zatrudniony: {BLACK}{MONTHYEAR} +STR_2351 :{WINDOW_COLOUR_2}Skoszone trawniki: {BLACK}{COMMA16} +STR_2352 :{WINDOW_COLOUR_2}Podlane ogrody: {BLACK}{COMMA16} +STR_2353 :{WINDOW_COLOUR_2}Sprzątnięte śmieci: {BLACK}{COMMA16} +STR_2354 :{WINDOW_COLOUR_2}Opróżnione kosze: {BLACK}{COMMA16} +STR_2355 :{WINDOW_COLOUR_2}Naprawione atrakcje: {BLACK}{COMMA16} +STR_2356 :{WINDOW_COLOUR_2}Skontrolowane atrakcje: {BLACK}{COMMA16} +STR_2357 :Dom STR_2358 :Jednostki STR_2359 :Prawdziwe wartości STR_2360 :{WINDOW_COLOUR_2}Rozdzielczość: @@ -2431,49 +2442,52 @@ STR_2405 :Build 10 roller coasters of a given length STR_2406 :Finish building 5 roller coasters STR_2407 :Repay loan and achieve a given park value STR_2408 :Monthly profit from food/merchandise -STR_2409 :{WINDOW_COLOUR_2}Marketing campaigns in operation -STR_2410 :{BLACK}None -STR_2411 :{WINDOW_COLOUR_2}Marketing campaigns available -STR_2412 :{SMALLFONT}{BLACK}Start this marketing campaign -STR_2413 :{BLACK}({CURRENCY2DP} per week) -STR_2414 :(Not Selected) -STR_2415 :{WINDOW_COLOUR_2}Ride: -STR_2416 :{WINDOW_COLOUR_2}Item: -STR_2417 :{WINDOW_COLOUR_2}Length of time: -STR_2418 :Free entry to {STRINGID} -STR_2419 :Free ride on {STRINGID} -STR_2420 :Half-price entry to {STRINGID} -STR_2421 :Free {STRINGID} -STR_2422 :Advertising campaign for {STRINGID} -STR_2423 :Advertising campaign for {STRINGID} -STR_2424 :{WINDOW_COLOUR_2}Vouchers for free entry to the park -STR_2425 :{WINDOW_COLOUR_2}Vouchers for free rides on a particular ride -STR_2426 :{WINDOW_COLOUR_2}Vouchers for half-price entry to the park -STR_2427 :{WINDOW_COLOUR_2}Vouchers for free food or drink -STR_2428 :{WINDOW_COLOUR_2}Advertising campaign for the park -STR_2429 :{WINDOW_COLOUR_2}Advertising campaign for a particular ride -STR_2430 :{BLACK}Vouchers for free entry to {STRINGID} -STR_2431 :{BLACK}Vouchers for free ride on {STRINGID} -STR_2432 :{BLACK}Vouchers for half-price entry to {STRINGID} -STR_2433 :{BLACK}Vouchers for free {STRINGID} -STR_2434 :{BLACK}Advertising campaign for {STRINGID} -STR_2435 :{BLACK}Advertising campaign for {STRINGID} -STR_2436 :1 week -STR_2437 :2 weeks -STR_2438 :3 weeks -STR_2439 :4 weeks -STR_2440 :5 weeks -STR_2441 :6 weeks -STR_2442 :{BLACK}({STRINGID} remaining) -STR_2443 :{WINDOW_COLOUR_2}Cost per week: {BLACK}{CURRENCY2DP} -STR_2444 :{WINDOW_COLOUR_2}Total cost: {BLACK}{CURRENCY2DP} -STR_2445 :Start this marketing campaign -STR_2446 :{YELLOW}Your marketing campaign for free entry to the park has finished -STR_2447 :{YELLOW}Your marketing campaign for free rides on {STRINGID} has finished -STR_2448 :{YELLOW}Your marketing campaign for half-price entry to the park has finished -STR_2449 :{YELLOW}Your marketing campaign for free {STRINGID} has finished -STR_2450 :{YELLOW}Your advertising campaign for the park has finished -STR_2451 :{YELLOW}Your advertising campaign for {STRINGID} has finished +# ------------------------------------------ Polish start +STR_2409 :{WINDOW_COLOUR_2}Trwające kampanie marketingowe +STR_2410 :{BLACK}Brak +STR_2411 :{WINDOW_COLOUR_2}Dostępne kampanie marketingowe +STR_2412 :{SMALLFONT}{BLACK}Rozpocznij tą kampanię +STR_2413 :{BLACK}({CURRENCY2DP} tygodniowo) +STR_2414 :(Nie wybrano) +STR_2415 :{WINDOW_COLOUR_2}Atrakcja: +STR_2416 :{WINDOW_COLOUR_2}Przedmiot: +STR_2417 :{WINDOW_COLOUR_2}Czas trwania: +# I think they are only used in "Voucher for ___" strings, so lower case fits here better +STR_2418 :darmowe wejście do {STRINGID} +STR_2419 :darmową przejażdżkę {STRINGID} +STR_2420 :wejście do {STRINGID} za połowę ceny +STR_2421 :darmowe {STRINGID} +STR_2422 :Kampania reklamowa dla {STRINGID} +STR_2423 :Kampania reklamowa dla {STRINGID} +STR_2424 :{WINDOW_COLOUR_2}Kupony na darmowe wejście do parku +STR_2425 :{WINDOW_COLOUR_2}Kupony na darmową przejażdżkę wybraną atrakcję +STR_2426 :{WINDOW_COLOUR_2}Kupony na wejście do parku za połowę ceny +STR_2427 :{WINDOW_COLOUR_2}Kupony na darmowe jedzenie lub picie +STR_2428 :{WINDOW_COLOUR_2}Kampania reklamująca park +STR_2429 :{WINDOW_COLOUR_2}Kampania reklamująca wybraną przejażdżkę +STR_2430 :{BLACK}Kupony na darmowe wejście do {STRINGID} +STR_2431 :{BLACK}Kupony na darmową przejażdżkę {STRINGID} +STR_2432 :{BLACK}Kupony na wejście do {STRINGID} za połowę ceny +STR_2433 :{BLACK}Kupony na darmowe {STRINGID} +STR_2434 :{BLACK}Kampania reklamowa dla {STRINGID} +STR_2435 :{BLACK}Kampania reklamowa dla {STRINGID} +STR_2436 :1 tydzień +STR_2437 :2 tygodnie +STR_2438 :3 tygodnie +STR_2439 :4 tygodnie +STR_2440 :5 tygodnie +STR_2441 :6 tygodnie +STR_2442 :{BLACK}(został/y {STRINGID}) +STR_2443 :{WINDOW_COLOUR_2}Koszt tygodniowy: {BLACK}{CURRENCY2DP} +STR_2444 :{WINDOW_COLOUR_2}Koszt łączny: {BLACK}{CURRENCY2DP} +STR_2445 :Rozpocznij kampanię +STR_2446 :{YELLOW}Twoja kampania marketingowa na darmowe wejście do parku zakończyła się +STR_2447 :{YELLOW}Twoja kampania marketingowa na darmowe przejażdżki {STRINGID} zakończyła się +STR_2448 :{YELLOW}Twoja kampania marketingowa na wejście do parku za połowę ceny zakończyła się +STR_2449 :{YELLOW}Twoja kampania marketingowa na darmowe {STRINGID} zakończyła się +STR_2450 :{YELLOW}Twoja kmapania reklamująca park zakończyła się +STR_2451 :{YELLOW}Twoja kampania reklamująca {STRINGID} zakończyła się +# ------------------------------------------ Polish end STR_2452 :{WINDOW_COLOUR_2}Cash (less loan): {BLACK}{CURRENCY2DP} STR_2453 :{WINDOW_COLOUR_2}Cash (less loan): {RED}{CURRENCY2DP} STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - @@ -2704,37 +2718,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Never +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. STR_2711 :; STR_2712 := STR_2713 :, @@ -2742,56 +2756,62 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +# New strings (previously these were ???) +STR_2718 :(..) +STR_2719 :(nowy plik) +# sec, secs +STR_2720 :{UINT16}sek +STR_2721 :{UINT16}sek +# min+sec, min+secs, mins+sec, mins+secs +STR_2722 :{UINT16}min:{UINT16}sek +STR_2723 :{UINT16}min:{UINT16}sek +STR_2724 :{UINT16}min:{UINT16}sek +STR_2725 :{UINT16}min:{UINT16}sek +# min, mins +STR_2726 :{UINT16}min +STR_2727 :{UINT16}min +# hour+min, hour+mins, hours+min, hours+mins +STR_2728 :{UINT16}godz:{UINT16}min +STR_2729 :{UINT16}godz:{UINT16}min +STR_2730 :{UINT16}godz:{UINT16}min +STR_2731 :{UINT16}godz:{UINT16}min +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Rok {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Rok {COMMA16} +STR_2738 :Muzyka tytułowa: +STR_2739 :Brak +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :Nie znaleziono css50.dat +STR_2743 :Przekopiuj data\css17.dat z folderu RCT1 do data\css50.dat folderu instalacji RCT2. +# End of new strings STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? -STR_2757 :??? -STR_2758 :??? -STR_2759 :??? -# New strings used in the cheats window previously these were ??? +# New strings (previously these were ???) +STR_2749 :Mój nowy scenariusz +STR_2750 :Przenieś wszystkie do góry +STR_2751 :Przenieś wszystkie na dół +STR_2752 :Czysta trawa +STR_2753 :Skoszona trawa +STR_2754 :Podlej kwiaty +STR_2755 :Usuń wandalizm +STR_2756 :Usuń śmieci +STR_2757 :Wymuś słońce +STR_2758 :Wymuś burzę +STR_2759 :Mniejsze odstępy STR_2760 :+5K Pieniędzy STR_2761 :Płatne Wejście STR_2762 :Płatne Atrakcje STR_2763 :??? STR_2764 :Szczęśliwi Goście STR_2765 :Przypływ Gości -STR_2766 :??? +STR_2766 :Wygraj scenariusz STR_2767 :Zablokuj Klimat STR_2768 :Odblokuj Klimat STR_2769 :Otwórz Park @@ -2801,12 +2821,12 @@ STR_2772 :Zwiększ Prędkość Gry STR_2773 :Okno STR_2774 :Pełny ekran STR_2775 :Pełny ekran w oknie -STR_2776 :Język +STR_2776 :Język: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +STR_2779 :Podgląd #{COMMA16} +STR_2780 :Dodatkowe okno podglądu # End of new strings -STR_2779 :??? -STR_2780 :??? STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + @@ -3137,9 +3157,11 @@ STR_3103 :Can't re-paint this... STR_3104 :{SMALLFONT}{BLACK}List rides STR_3105 :{SMALLFONT}{BLACK}List shops and stalls STR_3106 :{SMALLFONT}{BLACK}List information kiosks and other guest facilities -STR_3107 :Close -STR_3108 :Test -STR_3109 :Open +# ------------------------------------------ Polish start +STR_3107 :Zamknij +STR_3108 :Testuj +STR_3109 :Otwórz +# ------------------------------------------ Polish end STR_3110 :{WINDOW_COLOUR_2}Block Sections: {BLACK}{COMMA16} STR_3111 :{SMALLFONT}{BLACK}Click on design to build it STR_3112 :{SMALLFONT}{BLACK}Click on design to rename or delete it @@ -3484,3 +3506,164 @@ STR_3443 :Strona 4 STR_3444 :Strona 5 STR_3445 :Ustaw obszar do patrolowania STR_3446 :Wyłącz patrolowanie +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renew rides +STR_5124 :No Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +#Thousands separator +STR_5151 :. +#Decimal separator +STR_5152 :, +STR_5153 :Colour schemes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpaths +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear diff --git a/data/language/spanish_sp.txt b/data/language/spanish_sp.txt index bd27de53b6..9e3b0cbb9c 100644 --- a/data/language/spanish_sp.txt +++ b/data/language/spanish_sp.txt @@ -1065,7 +1065,7 @@ STR_1060 :Invalid ride/attraction name STR_1061 :Normal mode STR_1062 :Continuous circuit mode STR_1063 :Reverse-Incline launched shuttle mode -STR_1064 :Powered launch +STR_1064 :Powered launch (passing station) STR_1065 :Shuttle mode STR_1066 :Boat hire mode STR_1067 :Upward launch @@ -1097,7 +1097,7 @@ STR_1092 :Downward launch STR_1093 :Crooked house mode STR_1094 :Freefall drop mode STR_1095 :Continuous circuit block sectioned mode -STR_1096 :Powered launch +STR_1096 :Powered launch (without passing station) STR_1097 :Powered launch block sectioned mode STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} @@ -1778,7 +1778,7 @@ STR_1773 :Only one on-ride photo section allowed per ride STR_1774 :Only one cable lift hill allowed per ride STR_1775 :Off STR_1776 :On -STR_1777 :{WINDOW_COLOUR_2}Music: +STR_1777 :{WINDOW_COLOUR_2}Music STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigre costume @@ -2342,7 +2342,7 @@ STR_2337 :Deutschmark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseta (Pts) STR_2340 :Lira (L) -STR_2341 :Guilders (Dfl.) +STR_2341 :Guilders (fl.) STR_2342 :Krona (kr) STR_2343 :Euros ({EURO}) STR_2344 :Imperial @@ -2681,37 +2681,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Never +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. STR_2711 :; STR_2712 := STR_2713 :, @@ -2719,48 +2719,48 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(up) +STR_2719 :(new file) +STR_2720 :{UINT16}sec +STR_2721 :{UINT16}secs +STR_2722 :{UINT16}min:{UINT16}sec +STR_2723 :{UINT16}min:{UINT16}secs +STR_2724 :{UINT16}mins:{UINT16}sec +STR_2725 :{UINT16}mins:{UINT16}secs +STR_2726 :{UINT16}min +STR_2727 :{UINT16}mins +STR_2728 :{UINT16}hour:{UINT16}min +STR_2729 :{UINT16}hour:{UINT16}mins +STR_2730 :{UINT16}hours:{UINT16}min +STR_2731 :{UINT16}hours:{UINT16}mins +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, año {COMMA16} +STR_2737 :{STRINGID} {MONTH}, año {COMMA16} +STR_2738 :Title screen music: +STR_2739 :None +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat not found +STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat in your RCT2 installation. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? -STR_2757 :??? -STR_2758 :??? -STR_2759 :??? +STR_2749 :My new scenario +STR_2750 :Move all items to top +STR_2751 :Move all items to bottom +STR_2752 :Clear grass +STR_2753 :Mowed grass +STR_2754 :Water plants +STR_2755 :Fix vandalism +STR_2756 :Remove litter +STR_2757 :Force Sun +STR_2758 :Force Thunder +STR_2759 :Zero Clearance # New strings used in the cheats window previously these were ??? STR_2760 :+5K Money STR_2761 :Pay For Entrance @@ -2768,7 +2768,7 @@ STR_2762 :Pay For Rides STR_2763 :??? STR_2764 :Happy Guests STR_2765 :Large Tram -STR_2766 :??? +STR_2766 :Win scenario STR_2767 :Freeze Climate STR_2768 :Unfreeze Climate STR_2769 :Open Park @@ -2778,12 +2778,12 @@ STR_2772 :Faster Gamespeed STR_2773 :Windowed STR_2774 :Fullscreen STR_2775 :Fullscreen (desktop) -STR_2776 :Language +STR_2776 :Language: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings -STR_2779 :??? -STR_2780 :??? +STR_2779 :Viewport #{COMMA16} +STR_2780 :Extra viewport STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + @@ -3450,3 +3450,165 @@ STR_3443 :Page 4 STR_3444 :Page 5 STR_3445 :Set Patrol Area STR_3446 :Cancelar Patrol Area + +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renew rides +STR_5124 :No Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +#Thousands separator +STR_5151 :. +#Decimal separator +STR_5152 :, +STR_5153 :Colour schemes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpaths +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear diff --git a/data/language/swedish.txt b/data/language/swedish.txt index c216a2da66..0d50bc975d 100644 --- a/data/language/swedish.txt +++ b/data/language/swedish.txt @@ -1,4 +1,4 @@ -# STR_XXXX part is read and XXXX becomes the string id number. +# STR_XXXX part is read and XXXX becomes the string id number. # Everything after the colon and before the new line will be saved as the string. # Use # at the beginning of a line to leave a comment. STR_0000 : @@ -555,7 +555,7 @@ STR_0550 : STR_0551 : STR_0552 : STR_0553 : -STR_0554 :Vagnen acceleras ut ur stationen på en platt bana med hjälp av linjärmotorer, sen åker den vertikalt uppåt tills gravitationen tar över och vagnen åker tillbaka till stationen +STR_0554 :Vagnen accelereras ut ur stationen på en platt bana med hjälp av linjärmotorer, sen åker den vertikalt uppåt tills gravitationen tar över och vagnen åker tillbaka till stationen STR_0555 : STR_0556 : STR_0557 : @@ -576,7 +576,7 @@ STR_0571 : STR_0572 : STR_0573 : STR_0574 : -STR_0575 :Motoriserade tåg som hänger från en enkelspårig bana tranporterar folk runt om i parken +STR_0575 :Motoriserade tåg som hänger från en enkelspårig bana transporterar folk runt om i parken STR_0576 : STR_0577 : STR_0578 :Vagnar åker runt en bana omgiven av ringar utför branta nedförsbackar och skruvar @@ -1181,7 +1181,7 @@ STR_1175 :Kan inte bygga på en sluttande gångväg STR_1176 :Kan inte bygga gångväg här... STR_1177 :Kan inte ta bort gångvägen här... STR_1178 :Markens sluttning är inte lämplig -STR_1179 :Gånvägen är i vägen +STR_1179 :Gångvägen är i vägen STR_1180 :Kan inte bygga det här under vatten! STR_1181 :Gångvägar STR_1182 :Sort @@ -1780,7 +1780,7 @@ STR_1773 :Bara en fotosektion tillåten per åktur STR_1774 :Bara en uppskjutskulle tillåten per åktur STR_1775 :Av STR_1776 :På -STR_1777 :{WINDOW_COLOUR_2}Musik: +STR_1777 :{WINDOW_COLOUR_2}Musik STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Pandadräkt STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigerdräkt @@ -2344,7 +2344,7 @@ STR_2337 :Deutschmark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseta (Pts) STR_2340 :Lira (L) -STR_2341 :Guilders (Dfl.) +STR_2341 :Guilders (fl.) STR_2342 :Kronor (kr) STR_2343 :Euros ({EURO}) STR_2344 :Brittiska @@ -2683,37 +2683,37 @@ STR_2676 :??? STR_2677 :??? STR_2678 :??? STR_2679 :??? -STR_2680 :??? -STR_2681 :??? -STR_2682 :??? -STR_2683 :??? -STR_2684 :??? -STR_2685 :??? -STR_2686 :??? -STR_2687 :??? -STR_2688 :??? -STR_2689 :??? -STR_2690 :??? -STR_2691 :??? -STR_2692 :??? -STR_2693 :??? -STR_2694 :??? -STR_2695 :??? -STR_2696 :??? +STR_2680 :All research complete +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by 5,000 +STR_2682 :{MEDIUMFONT}{BLACK}Toggle between Free and Paid Entry +STR_2683 :{MEDIUMFONT}{BLACK}Increases every peeps happiness to max +STR_2684 :{MEDIUMFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Low: +STR_2687 :{WINDOW_COLOUR_2}High: +STR_2688 :{WINDOW_COLOUR_2}Base Frequency: +STR_2689 :{WINDOW_COLOUR_2}Octaves: +STR_2690 :Map Generation +STR_2691 :{WINDOW_COLOUR_2}Base height: +STR_2692 :{WINDOW_COLOUR_2}Water level: +STR_2693 :{WINDOW_COLOUR_2}Terrain: +STR_2694 :Generate +STR_2695 :Random terrain +STR_2696 :Place trees STR_2697 :??? STR_2698 :??? STR_2699 :??? -STR_2700 :??? -STR_2701 :??? -STR_2702 :??? -STR_2703 :??? -STR_2704 :??? -STR_2705 :??? -STR_2706 :??? -STR_2707 :??? -STR_2708 :??? -STR_2709 :??? -STR_2710 :??? +STR_2700 :Autosave frequency: +STR_2701 :Every week +STR_2702 :Every 2 weeks +STR_2703 :Every month +STR_2704 :Every 4 months +STR_2705 :Every year +STR_2706 :Never +STR_2707 :Open new window +STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? +STR_2709 :Overwrite +STR_2710 :Type the name of the file. STR_2711 :; STR_2712 := STR_2713 :, @@ -2721,48 +2721,49 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :??? -STR_2719 :??? -STR_2720 :??? -STR_2721 :??? -STR_2722 :??? -STR_2723 :??? -STR_2724 :??? -STR_2725 :??? -STR_2726 :??? -STR_2727 :??? -STR_2728 :??? -STR_2729 :??? -STR_2730 :??? -STR_2731 :??? -STR_2732 :??? -STR_2733 :??? -STR_2734 :??? -STR_2735 :??? -STR_2736 :??? -STR_2737 :??? -STR_2738 :??? -STR_2739 :??? -STR_2740 :??? -STR_2741 :??? -STR_2742 :??? -STR_2743 :??? +STR_2718 :(up) +STR_2719 :(new file) +STR_2720 :{UINT16}sec +STR_2721 :{UINT16}secs +STR_2722 :{UINT16}min:{UINT16}sec +STR_2723 :{UINT16}min:{UINT16}secs +STR_2724 :{UINT16}mins:{UINT16}sec +STR_2725 :{UINT16}mins:{UINT16}secs +STR_2726 :{UINT16}min +STR_2727 :{UINT16}mins +STR_2728 :{UINT16}hour:{UINT16}min +STR_2729 :{UINT16}hour:{UINT16}mins +STR_2730 :{UINT16}hours:{UINT16}min +STR_2731 :{UINT16}hours:{UINT16}mins +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Year {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Year {COMMA16} +STR_2738 :Title screen music: +STR_2739 :None +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat not found +STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat in your RCT2 installation. STR_2744 :[ STR_2745 :\ STR_2746 :] STR_2747 :{ENDQUOTES} STR_2748 :Bar -STR_2749 :??? -STR_2750 :??? -STR_2751 :??? -STR_2752 :??? -STR_2753 :??? -STR_2754 :??? -STR_2755 :??? -STR_2756 :??? -STR_2757 :??? -STR_2758 :??? -STR_2759 :??? +STR_2749 :My new scenario +# New strings used in the cheats window previously these were ??? +STR_2750 :Move all items to top +STR_2751 :Move all items to bottom +STR_2752 :Clear grass +STR_2753 :Mowed grass +STR_2754 :Water plants +STR_2755 :Fix vandalism +STR_2756 :Remove litter +STR_2757 :Force Sun +STR_2758 :Force Thunder +STR_2759 :Zero Clearance # New strings used in the cheats window previously these were ??? STR_2760 :+5K Pengar STR_2761 :Betala För Entré @@ -2770,22 +2771,22 @@ STR_2762 :Betala För Åkturer STR_2763 :??? STR_2764 :Glada Gäster STR_2765 :Stort Tåg -STR_2766 :??? +STR_2766 :Win scenario STR_2767 :Frys Klimat STR_2768 :Avfrys klimat STR_2769 :Öppna Park STR_2770 :Stäng Park -STR_2771 :Långsammare Spekhastighet +STR_2771 :Långsammare Spelhastighet STR_2772 :Snabbare Spelhastighet STR_2773 :Fönster STR_2774 :Fullskärm STR_2775 :Fullskärm (skrivbord) -STR_2776 :Språk +STR_2776 :Språk: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings -STR_2779 :??? -STR_2780 :??? +STR_2779 :Viewport #{COMMA16} +STR_2780 :Extra viewport STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + @@ -3454,3 +3455,164 @@ STR_3443 :Sida 4 STR_3444 :Sida 5 STR_3445 :Sätt Patrullområde STR_3446 :Avbryt Patrullområde +# New strings, cleaner +STR_5120 :Show finances button on toolbar +STR_5121 :Show research button on toolbar +STR_5122 :Show all vehicles sharing a track/ride type +STR_5123 :Renew rides +STR_5124 :No Six Flags +STR_5125 :All destructable +STR_5126 :Random title music +STR_5127 :{SMALLFONT}{BLACK}Disable land elevation +STR_5128 :Selection size +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Map size +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Fix all rides +STR_5133 :{SMALLFONT}{BLACK}Adjust smaller area of land rights +STR_5134 :{SMALLFONT}{BLACK}Adjust larger area of land rights +STR_5135 :{SMALLFONT}{BLACK}Buy land rights and construction rights +STR_5136 :Land rights +STR_5137 :Allow lift hill and launch speeds{NEWLINE}up to {VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :Disable brakes failure +STR_5141 :Disable all breakdowns +STR_5142 :Normal Speed +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Show cheats button on toolbar +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5150 :Enable debugging tools +#Thousands separator +STR_5151 : +#Decimal separator +STR_5152 :, +STR_5153 :Colour schemes... +STR_5154 :Hardware display +STR_5155 :Allow testing of unfinished tracks +STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the track is unfinished, does not apply to block sectioned modes +STR_5157 :Unlock all prices +STR_5158 :Quit to menu +STR_5159 :Exit OpenRCT2 +STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5161 :Date Format: +STR_5162 :Day/Month/Year +STR_5163 :Month/Day/Year +STR_5164 :Twitch Channel name +STR_5165 :Name peeps after followers +STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers +STR_5167 :Track follower peeps +STR_5168 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after channel's Twitch followers +STR_5169 :Name peeps after people in Twitch chat +STR_5170 :{SMALLFONT}{BLACK}Will name peeps after people in Twitch chat +STR_5171 :Track chat peeps +STR_5172 :{SMALLFONT}{BLACK}Will turn on tracking information for guests named after Twitch chat participants +STR_5173 :Pull Twitch chat as news +STR_5174 :{SMALLFONT}{BLACK}Will use Twitch chat messages preceded by !news for in game notifications +STR_5175 :Input the name of your Twitch channel +STR_5176 :Enable Twitch integration +STR_5177 :Fullscreen mode: +STR_5178 :{SMALLFONT}{BLACK}Show financial cheats +STR_5179 :{SMALLFONT}{BLACK}Show guest cheats +STR_5180 :{SMALLFONT}{BLACK}Show park cheats +STR_5181 :{SMALLFONT}{BLACK}Show ride cheats +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Water level +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Finances +STR_5188 :New Campaign +STR_5189 :Research +STR_5190 :Map +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Water +STR_5195 :Clear Scenery +STR_5196 :Land Rights +STR_5197 :Scenery +STR_5198 :Footpath +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Ride +STR_5204 :Ride List +STR_5205 :Guest +STR_5206 :Guest List +STR_5207 :Staff +STR_5208 :Staff List +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Invention List +STR_5212 :Scenario Options +STR_5213 :Objective Options +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Cheats +STR_5218 :Themes +STR_5219 :Options +STR_5220 :Keyboard Shortcuts +STR_5221 :Change Keyboard Shortcut +STR_5222 :Load/Save +STR_5223 :Save Prompt +STR_5224 :Demolish Ride Prompt +STR_5225 :Fire Staff Prompt +STR_5226 :Track Delete Prompt +STR_5227 :Save Overwrite Prompt +STR_5228 :{SMALLFONT}{BLACK}Main UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Tools +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Miscellaneous +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Settings +STR_5236 :Window: +STR_5237 :Palette: +STR_5238 :Current Theme: +STR_5239 :Duplicate +STR_5240 :Enter a name for the theme +STR_5241 :Can't change this theme +STR_5242 :Theme name already exists +STR_5243 :Invalid characters used +STR_5244 :Themes +STR_5245 :Top Toolbar +STR_5246 :Bottom Toolbar +STR_5247 :Track Editor Bottom Toolbar +STR_5248 :Scenario Editor Bottom Toolbar +STR_5249 :Title Menu Buttons +STR_5250 :Title Exit Button +STR_5251 :Title Options Button +STR_5252 :Title Scenario Selection +STR_5253 :Park Information +STR_5254 :Add nausea +STR_5255 :{MEDIUMFONT}{BLACK}All peeps become nauseous +STR_5256 :Create a new theme to make changes to +STR_5257 :{SMALLFONT}{BLACK}Create a new theme based on the current one +STR_5258 :{SMALLFONT}{BLACK}Delete the current theme +STR_5259 :{SMALLFONT}{BLACK}Rename the current theme +STR_5260 :Giant Screenshot +STR_5261 :Filter +STR_5262 :Wacky Worlds +STR_5263 :Time Twister +STR_5264 :Custom +STR_5265 :{SMALLFONT}{BLACK}Select which content sources are visible +STR_5266 :{SMALLFONT}{BLACK}Display +STR_5267 :{SMALLFONT}{BLACK}Culture and Units +STR_5268 :{SMALLFONT}{BLACK}Audio +STR_5269 :{SMALLFONT}{BLACK}Controls +STR_5270 :{SMALLFONT}{BLACK}Miscellaneous +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Footpaths +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Clear diff --git a/data/title/achilleshiel.sv6 b/data/title/achilleshiel.sv6 new file mode 100644 index 0000000000..24ce7be588 Binary files /dev/null and b/data/title/achilleshiel.sv6 differ diff --git a/data/title/faas.sv6 b/data/title/faas.sv6 new file mode 100644 index 0000000000..bb7ce80cb7 Binary files /dev/null and b/data/title/faas.sv6 differ diff --git a/data/title/mci.sv6 b/data/title/mci.sv6 new file mode 100644 index 0000000000..95008afc08 Binary files /dev/null and b/data/title/mci.sv6 differ diff --git a/data/title/pfckrutonium1.sv6 b/data/title/pfckrutonium1.sv6 new file mode 100644 index 0000000000..25ba708455 Binary files /dev/null and b/data/title/pfckrutonium1.sv6 differ diff --git a/data/title/pfckrutonium2.sv6 b/data/title/pfckrutonium2.sv6 new file mode 100644 index 0000000000..59de4c0c38 Binary files /dev/null and b/data/title/pfckrutonium2.sv6 differ diff --git a/data/title/poke.sv6 b/data/title/poke.sv6 new file mode 100644 index 0000000000..f9702ff6dc Binary files /dev/null and b/data/title/poke.sv6 differ diff --git a/data/title/rid6.sv6 b/data/title/rid6.sv6 new file mode 100644 index 0000000000..c83a3af928 Binary files /dev/null and b/data/title/rid6.sv6 differ diff --git a/data/title/script.txt b/data/title/script.txt new file mode 100644 index 0000000000..861dbd25e8 --- /dev/null +++ b/data/title/script.txt @@ -0,0 +1,106 @@ +# OpenRCT2 0.0.2 Title Sequence Script +# Arranged by IntelOrca + +# PFCKrutonium +LOAD pfckrutonium1.sv6 +LOCATION 7 41 +WAIT 15 +LOCATION 49 15 +ROTATE 1 +WAIT 10 + +# Achilleshiel +LOAD achilleshiel.sv6 +LOCATION 25 77 +WAIT 10 + +LOCATION 36 58 +ROTATE 3 +WAIT 12 + +LOCATION 64 40 +ROTATE 1 +WAIT 8 + +# DUSTY GREENS +LOAD triggerdeath.sv6 +LOCATION 63 68 +WAIT 14 + +ROTATE 1 +WAIT 16 + +LOCATION 28 26 +ROTATE 2 +WAIT 10 + +LOCATION 61 33 +ROTATE 2 +WAIT 8 + +# PFCKrutonium +LOAD pfckrutonium2.sv6 +LOCATION 116 58 +WAIT 14 + +ROTATE 1 +WAIT 12 + +# Shotguns (http://www.nedesigns.com/park/3107/rougarou/) +LOAD shotguns.sv6 +LOCATION 20 13 +WAIT 16 + +# Faas (http://www.nedesigns.com/park/2996/lucky-lake-amusement-park/) +LOAD faas.sv6 +LOCATION 42 11 +WAIT 10 + +LOCATION 30 18 +ROTATE 1 +WAIT 16 + +LOCATION 17 71 +ROTATE 2 +WAIT 12 + +LOCATION 88 68 +WAIT 12 + +# MCI (http://www.nedesigns.com/park/2973/maerchen-paradies/) +LOAD mci.sv6 +LOCATION 46 60 +WAIT 16 + +LOCATION 78 43 +ROTATE 2 +WAIT 12 + +LOCATION 76 32 +ROTATE 1 +WAIT 8 + +# Ride6 (http://www.nedesigns.com/park/2545/banana-valley/) +LOAD rid6.sv6 +LOCATION 56 34 +WAIT 10 + +LOCATION 48 4 +WAIT 4 + +LOCATION 10 29 +ROTATE 1 +WAIT 12 + +# Poke (http://www.nedesigns.com/park/2967/mystic-mountain/) +LOAD poke.sv6 +LOCATION 43 83 +WAIT 16 + +LOCATION 63 35 +ROTATE 3 +WAIT 12 + +LOCATION 12 47 +ROTATE 3 +WAIT 20 \ No newline at end of file diff --git a/data/title/shotguns.sv6 b/data/title/shotguns.sv6 new file mode 100644 index 0000000000..a40b6425a4 Binary files /dev/null and b/data/title/shotguns.sv6 differ diff --git a/data/title/triggerdeath.sv6 b/data/title/triggerdeath.sv6 new file mode 100644 index 0000000000..ff00a979bb Binary files /dev/null and b/data/title/triggerdeath.sv6 differ diff --git a/distribution/changelog.txt b/distribution/changelog.txt new file mode 100644 index 0000000000..ea635d13f8 --- /dev/null +++ b/distribution/changelog.txt @@ -0,0 +1,45 @@ +0.0.2-beta (2015-06-21) +------------------------------------------------------------------------ +- Feature: Intro sequence does not show by default. +- Feature: New title screen logo. +- Feature: New title sequence (RCT2 version also still available). +- Feature: Title sequence music can now be disabled or changed to the RollerCoaster Tycoon 1 theme music. +- Feature: In-game console. +- Feature: Improved settings window with tab interface. +- Feature: Ability to change language while in game. +- Feature: Text input is now an in-game window. +- Feature: Toggle between software and hardware video mode. +- Feature: Toggle between resizeable window and fullscreen. +- Feature: Windows now snap to the borders of other windows when dragging (snap radius configurable). +- Feature: Interface colour themes. (Presets for RCT1 and RCT2 are included by default). +- Feature: Re-introduce traffic lights for close / test / open as a theme option. +- Feature: Show day as well as the month and year. +- Feature: Show month before day (e.g. March 14th, year 15) +- Feature: Exit OpenRCT2 to desktop. +- Feature: Game configuration, cache, scores and screenshots now saved in user documents directory under OpenRCT2. +- Feature: Auto-saving with frequency option. +- Feature: Ability to change game speed via toolbar or (+ and - keys). +- Feature: Finance window accessible from toolbar (enabled in settings). +- Feature: Research and development / research funding now accessible as a stand alone window without the requirement of the finances window. +- Feature: Extra viewport windows. +- Feature: Park window viewport is resizable. +- Feature: Land, water and ownership tool sizes can now be increased to 64x64. +- Feature: Mountain tool available in play mode. +- Feature: Buy land and construction rights land tool window. (Currently only in-game). +- Feature: Place scenery as a random cluster available in play mode. +- Feature: Increased limits for maximum of circuits per roller coaster to 20 and people on mazes to 64 +- Feature: Allow both types of powered launch (with and without passing the station) for every roller coaster that supported one type in RCT2. +- Feature: Allow testing of incomplete tracks. +- Feature: Cheats window (Ctrl-Alt-C) or by toolbar button (configurable). +- Feature: Cheats for almost every guest aspect (happiness, hunger, nausea tolerance, etc.) +- Feature: Cheat to allow maximum operating settings and lift hill speeds (410 km/h). +- Feature: Cheat to disable all breakdowns. +- Feature: Cheat to disable brakes failure. +- Feature: Cheat to fix all rides. +- Feature: Change available objects in-game (only available from console). +- Feature: Change research settings in-game (only available from console). +- Feature: (Random) map generator available in scenario editor, accessible via the view menu. +- Feature: RollerCoaster Tycoon 1 scenarios can now be opened in the scenario editor or by using the 'edit' command line action. +- Feature: The "have fun" objective can now be selected in the scenario editor. +- Feature: Twitch integration +- Fix: Litter bins now get full and require emptying by handymen. \ No newline at end of file diff --git a/distribution/known_issues.txt b/distribution/known_issues.txt new file mode 100644 index 0000000000..082aa54cc5 --- /dev/null +++ b/distribution/known_issues.txt @@ -0,0 +1,11 @@ +Release version: 0.0.2-beta +------------------------------------------------------------------------ +* Some sounds play at their maximum volume irrespective of the sound volume control. +* Sandbox mode does not support all map modifications. +* Zero clearance cheat results in drawing glitches. +* Build while paused mode does not support all game commands. +* Some text shown in the map is not translated to selected language. +* Scenario editor object selection window will show object names in the selected language at the time of building the object cache. (Deleting plugin.dat in Documents/OpenRCT2 will fix this) +* The game will run slower at high resolutions, particularly if there are many moving objects visible. + +Most bugs or limitations present in the original game have not yet been fixed or lifted. \ No newline at end of file diff --git a/distribution/readme.txt b/distribution/readme.txt new file mode 100644 index 0000000000..b08d4d7da7 --- /dev/null +++ b/distribution/readme.txt @@ -0,0 +1,162 @@ +Last updated: 2015-06-21 +Release version: 0.0.2-beta +------------------------------------------------------------------------ + + +Table of contents +----------------- +1.0) About +2.0) Contacting + * 2.1) Reporting bugs +3.0) Supported platforms +4.0) Installing and running OpenRCT2 +5.0) Development +6.0) Translation +7.0) Troubleshooting +8.0) Licensing +9.0) Credits + +1.0) About +---- ----- +OpenRCT2 is an amusement park simulation game based upon the popular game +RollerCoaster Tycoon 2, written by Chris Sawyer. It attempts to mimic the +original game as closely as possible while extending it with new features. + +OpenRCT2 is licensed under the GNU General Public License version 3.0, but +includes some 3rd party software under different licenses. See the section +"Licensing" below for details. + +2.0) Contacting +---- ---------- +The easiest way to contact the OpenRCT2 team is by submitting issues on GitHub +(https://github.com/OpenRCT2/OpenRCT2) in the form of questions or bug reports. +You can also chat with us on gitter (https://gitter.im/OpenRCT2/OpenRCT2). + +2.1) Reporting bugs +---- -------------- +GitHub is used for tracking bugs in OpenRCT2. Please check if the bug has +already been reported using the search functionality before submitting. + +When you are sure it is not already reported you should: + * Make sure you are running a recent version, i.e. run the latest stable or + nightly based on where you found the bug. + * Make sure you are not running a non-official binary, like a fork. + When you are playing with a fork you should report any bugs to the bug + tracker for that fork which is most likely another GitHub repository. + * Make it reproducible for the developers. In other words, create a savegame + in which you can reproduce the issue once loaded. It is very useful to give + us the crash.dmp, crash.sav, crash.log and crash screenshot which are + created on crashes. + * Check whether the bug is already reported on our bug tracker. This includes + searching for recently closed bug reports as the bug might already be fixed. + +After you have done all that you can report the bug. Please include the +following information in your bug report: + * OpenRCT2 version (PLEASE test the latest git develop build) + * Bug details, including instructions how to reproduce it + * Platform (Windows, Linux, FreeBSD, ...) and compiler (including version) if + you compiled OpenRCT2 yourself. + * The processor architecture of your OS (32 bits Windows, 64 bits Windows, + Linux on an ARM, Mac OS X on a PowerPC, ...) + * The language and culture your operating system is using. + * Attach a saved game *and* a screenshot if possible + * If this bug only occurred recently please note the last version without + the bug and the first version including the bug. That way we can fix it + quicker by looking at the changes made. + * Attach crash.dmp, crash.log and crash.sav. These files are usually created + next to your openrct2.cfg. The crash handler will tell you the location. + +3.0) Supported platforms +---- ------------------- +OpenRCT2 currently requires the original RollerCoaster Tycoon 2 binary. While +this is still the case, the only supported platform is Windows. OpenRCT2 can +still be played on other operating systems either via a virtual machine or a +compatibility layer application such as Wine. Further instructions can be found +on GitHub. + +4.0) Installing and running OpenRCT2 +---- ------------------------------ +Installing OpenRCT2 is fairly straightforward. Either you have downloaded an +archive which you have to extract to a directory where you want OpenRCT2 to +be installed, or you have downloaded an installer, which will automatically +extract OpenRCT2 in the given directory. + +OpenRCT2 requires an installation of RollerCoaster Tycoon 2 (RCT2) to run. You +must have either installed the original RCT2 disc, the GOG version or the steam +version. Alternatively you can manually specify the location of where your RCT2 +data files are. These may be directly copied of the original disc and placed in +a directory of your choice. + +When you start OpenRCT2 for the first time, it will look for the RCT2 data files +in the following locations: + - C:\Program Files\Infogrames\RollerCoaster Tycoon 2, + - C:\Program Files (x86)\Infogrames\RollerCoaster Tycoon 2, + - C:\Program Files\Infogrames Interactive\RollerCoaster Tycoon 2, + - C:\Program Files (x86)\Infogrames Interactive\RollerCoaster Tycoon 2, + - C:\Program Files\Atari\RollerCoaster Tycoon 2, + - C:\Program Files (x86)\Atari\RollerCoaster Tycoon 2, + - C:\GOG Games\RollerCoaster Tycoon 2 Triple Thrill Pack + - The location of the openrct2.exe (where OpenRCT2 was extracted/installed) + +If none of these locations are found, OpenRCT2 will ask you to manually specify +the directory. Alternatively after running OpenRCT2 for the first time, you can +edit openrct2.cfg in the OpenRCT2 sub directory of your documents folder to set +the RCT2 install path. + +If you are running Windows and have set a DPI scale, OpenRCT2 might look blury. +This is because OpenRCT2 currently uses the original RollerCoaster Tycoon 2 +binary as a application host. However you can manually configure this binary to +not be scaled. This will make the game more crisp, but may result in the +interface being too small to see clearly and less ergonomic to use. To stop DPI +scaling, right click the binary itself (openrct2.exe) in the install directory +or the OpenRCT2 shortcut either in your start menu or on your desktop and then +select properties. Select the compatibility tab, check +"Disable display scaling on high DPI settings" and then click OK. + +If you wish to use Steam Overlay or capture game for video recording or +streaming, you might have to enable hardware display in the options window. +This will still render the graphics on the CPU but the pixel data will be +displayed using either DirectX or OpenGL. This might slow down the game but can +also make the game look smoother. + +5.0) Development +---- ----------- +OpenRCT2 is an open-source collaborative project. It is developed voluntarily +and hosted on GitHub. If you would like to contribute to the development of +OpenRCT2, please read the readme file in the OpenRCT2 repository or on the main +GitHub page at (https://github.com/OpenRCT2/OpenRCT2). This gives more detailed +information about the project, its roadmap and how to compile the source code. + +6.0) Translation +---- ----------- +For more information about the game's translation and how to contribute, please +visit the GitHub page and wiki at (https://github.com/OpenRCT2/OpenRCT2). + +7.0) Troubleshooting +---- --------------- +If you are having problems running OpenRCT2, you can run OpenRCT2 in verbose +mode to view a detailed diagnostic log. This can be activated by running the +game via Command Prompt or PowerShell with the command line switch --verbose. + +This log can help pinpoint where a problem exists and is a useful resource if +you wish to ask online for help. + +8.0) Licensing +---- --------- +OpenRCT2 is licensed under the GNU General Public Licence version 3.0. For +the complete licence text, see the file 'licence.txt'. This licence applies +to all files in this distribution, except as noted below. + +argparse | MIT licence. +CuTest | zlib licence. +Jansson | MIT licence. +libcURL | MIT (or Modified BSD-style) licence. +libspeex | BSD-style license. +LodePNG | zlib licence. +SDL2 | zlib licence. + +Licences for sub-libraries used by the above may vary. For more information, visit the libraries' respective official websites. + +9.0) Credits +---- ------- +For the full list of contributors to OpenRCT2, see the file 'contributors.md'. \ No newline at end of file diff --git a/distribution/windows/build.ps1 b/distribution/windows/build.ps1 new file mode 100644 index 0000000000..e53b36e516 --- /dev/null +++ b/distribution/windows/build.ps1 @@ -0,0 +1,3 @@ +$path = Split-Path $Script:MyInvocation.MyCommand.Path +Write-Output "Building Windows Installer (NSIS script)"; +makensis /DVERSION_INCLUDE=$path\win32.txt $path\install.nsi > $path\win32.log; \ No newline at end of file diff --git a/distribution/windows/install.nsi b/distribution/windows/install.nsi new file mode 100644 index 0000000000..29177fc8a6 --- /dev/null +++ b/distribution/windows/install.nsi @@ -0,0 +1,508 @@ +# Version numbers to update +!define /ifndef APPV_MAJOR 0 +!define /ifndef APPV_MINOR 0 +!define /ifndef APPV_MAINT 2 +!define /ifndef APPV_BUILD 0 +!define /ifndef APPV_EXTRA "-beta" + +!define APPNAME "OpenRCT2" ; Define application name +!define APPVERSION "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}${APPV_EXTRA}" ; Define application version +!define APPVERSIONINTERNAL "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}.${APPV_BUILD}" ; Define application version in X.X.X.X +!include ${VERSION_INCLUDE} + +!define /ifndef APPURLLINK "https://github.com/OpenRCT2/OpenRCT2" +!define APPNAMEANDVERSION "${APPNAME} ${APPVERSION}" + +; Define root variable relative to installer +!define PATH_ROOT "..\..\" + +!define MUI_ICON "${PATH_ROOT}resources\logo\icon.ico" +!define MUI_UNICON "${PATH_ROOT}resources\logo\icon.ico" +!define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp" +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "top.bmp" + +BrandingText "OpenRCT2 Installer" +SetCompressor LZMA + +; Version Info +VIProductVersion "${APPVERSIONINTERNAL}" +VIAddVersionKey "ProductName" "OpenRCT2 ${APPBITS}-bit Installer for Windows ${EXTRA_VERSION}" +VIAddVersionKey "Comments" "Installs ${APPNAMEANDVERSION}" +VIAddVersionKey "CompanyName" "OpenRCT2 Developers" +VIAddVersionKey "FileDescription" "Installs ${APPNAMEANDVERSION}" +VIAddVersionKey "ProductVersion" "${APPVERSION}" +VIAddVersionKey "InternalName" "InstOpenRCT2-${APPARCH}" +VIAddVersionKey "FileVersion" "${APPVERSION}-${APPARCH}" +VIAddVersionKey "LegalCopyright" " " +; Main Install settings +Name "${APPNAMEANDVERSION} ${APPBITS}-bit for Windows ${EXTRA_VERSION}" + +; NOTE: Keep trailing backslash! +InstallDirRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Install Folder" +!ifndef OUTFILE + !define OUTFILE "openrct2-${APPVERSION}-${APPARCH}.exe" +!endif +OutFile "${OUTFILE}" +CRCCheck force + +ShowInstDetails show +ShowUninstDetails show + +RequestExecutionLevel admin + +Var SHORTCUTS + +; Modern interface settings +!include "MUI2.nsh" +!include "InstallOptions.nsh" +!include "WinVer.nsh" +!include "x64.nsh" + +!define MUI_ABORTWARNING +!define MUI_WELCOMEPAGE_TITLE_3LINES +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "..\..\licence.txt" + +!define MUI_COMPONENTSPAGE_SMALLDESC +!insertmacro MUI_PAGE_COMPONENTS + +!insertmacro MUI_PAGE_DIRECTORY + +ManifestDPIAware true + +;Start Menu Folder Page Configuration +!define MUI_STARTMENUPAGE_DEFAULTFOLDER $SHORTCUTS +!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKEY_LOCAL_MACHINE" +!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" +!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Shortcut Folder" + +!insertmacro MUI_PAGE_STARTMENU "OpenRCT2" $SHORTCUTS + +!insertmacro MUI_PAGE_INSTFILES + +!define MUI_FINISHPAGE_TITLE_3LINES +!define MUI_FINISHPAGE_RUN_TEXT "Run ${APPNAMEANDVERSION} now!" +!define MUI_FINISHPAGE_RUN "$INSTDIR\openrct2.exe" +!define MUI_FINISHPAGE_LINK "Visit the OpenRCT2 site for more information" +!define MUI_FINISHPAGE_LINK_LOCATION "${APPURLLINK}" +!define MUI_FINISHPAGE_NOREBOOTSUPPORT +!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\readme.txt" +!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED +!define MUI_WELCOMEFINISHPAGE_CUSTOMFUNCTION_INIT DisableBack + +!insertmacro MUI_PAGE_FINISH +!define MUI_PAGE_HEADER_TEXT "Uninstall ${APPNAMEANDVERSION}" +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +; Set languages (first is default language) +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_RESERVEFILE_LANGDLL + +;-------------------------------------------------------------- +; (Core) OpenRCT2 install section. Copies all internal game data +Section "!OpenRCT2" Section1 + ; Make sure to be upgraded OpenRCT2 is not running + Call CheckOpenRCT2Running + + ; Overwrite files by default, but don't complain on failure + SetOverwrite try + + SetShellVarContext all + + ; Copy language files + SetOutPath "$INSTDIR\data\language\" + File ${PATH_ROOT}data\language\*.txt + + ; Copy data files + SetOutPath "$INSTDIR\data\" + File /r ${PATH_ROOT}data\* + + ; Copy the rest of the stuff + SetOutPath "$INSTDIR\" + + ; Copy curl ca file + File ..\..\curl-ca-bundle.crt + + ; Copy text files + File ..\changelog.txt + Push "$INSTDIR\changelog.txt" + Call unix2dos + File ..\..\licence.txt + Push "$INSTDIR\licence.txt" + Call unix2dos + File ..\readme.txt + Push "$INSTDIR\readme.txt" + Call unix2dos + File ..\..\contributors.md + Push "$INSTDIR\contributors.md" + Call unix2dos + + ; Copy executable + File /oname=openrct2.exe ${BINARY_DIR}\openrct2.exe + File /oname=openrct2.dll ${BINARY_DIR}\openrct2.dll + File /oname=SDL2.dll ${BINARY_DIR}\SDL2.dll + + ; Create the Registry Entries + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Comments" "Visit ${APPURLLINK}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "DisplayIcon" "$INSTDIR\openrct2.exe,0" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "DisplayName" "OpenRCT2 ${APPVERSION}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "DisplayVersion" "${APPVERSION}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "HelpLink" "${APPURLLINK}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Install Folder" "$INSTDIR" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Publisher" "OpenRCT2" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Shortcut Folder" "$SHORTCUTS" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "UninstallString" "$INSTDIR\uninstall.exe" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "URLInfoAbout" "${APPURLLINK}" + ; This key sets the Version DWORD that new installers will check against + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Version" "${APPVERSIONINTERNAL}" + + !insertmacro MUI_STARTMENU_WRITE_BEGIN "OpenRCT2" + CreateShortCut "$DESKTOP\OpenRCT2.lnk" "$INSTDIR\openrct2.exe" + CreateDirectory "$SMPROGRAMS\$SHORTCUTS" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\OpenRCT2.lnk" "$INSTDIR\openrct2.exe" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Uninstall.lnk" "$INSTDIR\uninstall.exe" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Readme.lnk" "$INSTDIR\Readme.txt" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Changelog.lnk" "$INSTDIR\Changelog.txt" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Contributors.lnk" "$INSTDIR\contributors.md" + !insertmacro MUI_STARTMENU_WRITE_END +SectionEnd + +;------------------------------------------- +; Install the uninstaller (option is hidden) +Section -FinishSection + WriteUninstaller "$INSTDIR\uninstall.exe" +SectionEnd + +; Modern install component descriptions +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${Section1} "Minimal OpenRCT2 installation in English. You must have RollerCoaster Tycoon 2 installed." +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +;----------------------------------------------- +; Uninstall section, deletes all installed files +Section "Uninstall" + SetShellVarContext all + + ; Remove from registry... + !insertmacro MUI_STARTMENU_GETFOLDER "OpenRCT2" $SHORTCUTS + ReadRegStr $SHORTCUTS HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Shortcut Folder" + + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" + + ; Delete self + Delete "$INSTDIR\uninstall.exe" + + ; Delete Shortcuts + Delete "$DESKTOP\OpenRCT2.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\OpenRCT2.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Uninstall.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Readme.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Changelog.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Contributors.lnk" + + ; Clean up OpenRCT2 dir + Delete "$INSTDIR\changelog.txt" + Delete "$INSTDIR\readme.txt" + Delete "$INSTDIR\contributors.md" + Delete "$INSTDIR\openrct2.exe" + Delete "$INSTDIR\openrct2.dll" + Delete "$INSTDIR\SDL2.dll" + Delete "$INSTDIR\licence.txt" + Delete "$INSTDIR\INSTALL.LOG" + Delete "$INSTDIR\crash.log" + Delete "$INSTDIR\crash.dmp" + + ; Data files + Delete "$INSTDIR\data\language\*.txt" + Delete "$INSTDIR\data\title\*.*" + + ; Remove remaining directories + RMDir "$SMPROGRAMS\$SHORTCUTS" + RMDir "$INSTDIR\data" + RMDir "$INSTDIR" + +SectionEnd + +;------------------------------------------------------------------------------- +; Determine windows version, returns "win9x" if Win9x/Me/2000/XP SP2- or "winnt" for the rest on the stack +Function GetWindowsVersion + ClearErrors + StrCpy $R0 "win9x" + + ${If} ${RunningX64} + goto WinNT + ${EndIf} + + ${If} ${IsNT} + ${If} ${IsWinXP} + ${AndIf} ${AtLeastServicePack} 3 + ${OrIf} ${AtLeastWin2003} + GoTo WinNT + ${EndIf} + ${EndIf} + GoTo Done +WinNT: + StrCpy $R0 "winnt" +Done: + Push $R0 +FunctionEnd + +;------------------------------------------------------------------------------- +; Check whether we're not running an installer for 64 bits on 32 bits and vice versa +Function CheckProcessorArchitecture + ClearErrors + ${If} ${RunningX64} + IntCmp ${APPBITS} 64 Done 0 + MessageBox MB_YESNO|MB_ICONINFORMATION "You are trying to install the 32-bit OpenRCT2 on a 64-bit operating system. This is not advised, but will work with reduced capabilities. We suggest that you download the correct version. Do you really want to continue?" IDYES Done IDNO Abort + ${Else} + IntCmp ${APPBITS} 64 0 Done + MessageBox MB_YESNO|MB_ICONSTOP "You are trying to install the 64-bit OpenRCT2 on a 32-bit operating system. This is not going to work. Please download the correct version. Do you really want to continue?" IDYES Done IDNO Abort + ${EndIf} + GoTo Done +Abort: + Quit +Done: +FunctionEnd + +;------------------------------------------------------------------------------- +; Check whether we're not running an installer for NT on 9x and vice versa +Function CheckWindowsVersion + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "win9x" 0 WinNT + ClearErrors + StrCmp ${APPARCH} "win9x" Done 0 + MessageBox MB_YESNO|MB_ICONSTOP "You are trying to install the Windows XP SP3, Vista, 7 and 8.1 version on Windows 95, 98, ME, 2000 and XP without SP3. This is will not work. Please download the correct version. Do you really want to continue?" IDYES Done IDNO Abort + GoTo Done +WinNT: + ClearErrors + StrCmp ${APPARCH} "win9x" 0 Done + MessageBox MB_YESNO|MB_ICONEXCLAMATION "You are trying to install the Windows 95, 98, 2000 and XP without SP3 version on Windows XP SP3, Vista, 7 and 8.1. This is not advised, but will work with reduced capabilities. We suggest that you download the correct version. Do you really want to continue?" IDYES Done IDNO Abort +Abort: + Quit +Done: +FunctionEnd + +;------------------------------------------------------------------------------- +; Check whether OpenRCT2 is running +Function CheckOpenRCT2Running + IfFileExists "$INSTDIR\openrct2.exe" 0 Done +Retry: + FindProcDLL::FindProc "openrct2.exe" + Pop $R0 + IntCmp $R0 1 0 Done + ClearErrors + Delete "$INSTDIR\openrct2.exe" + IfErrors 0 Done + ClearErrors + MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "OpenRCT2 is running. Please close it and retry." IDRETRY Retry + Abort +Done: +FunctionEnd + +;------------------------------------------------------------------------------- +; strips all CRs +; and then converts all LFs into CRLFs +; (this is roughly equivalent to "cat file | dos2unix | unix2dos") +; +; usage: +; Push "infile" +; Call unix2dos +; +; beware that this function destroys $0 $1 $2 +Function unix2dos + ClearErrors + + Pop $2 + Rename $2 $2.U2D + FileOpen $1 $2 w + + FileOpen $0 $2.U2D r + + Push $2 ; save name for deleting + + IfErrors unix2dos_done + + ; $0 = file input (opened for reading) + ; $1 = file output (opened for writing) + +unix2dos_loop: + ; read a byte (stored in $2) + FileReadByte $0 $2 + IfErrors unix2dos_done ; EOL + ; skip CR + StrCmp $2 13 unix2dos_loop + ; if LF write an extra CR + StrCmp $2 10 unix2dos_cr unix2dos_write + +unix2dos_cr: + FileWriteByte $1 13 + +unix2dos_write: + ; write byte + FileWriteByte $1 $2 + ; read next byte + Goto unix2dos_loop + +unix2dos_done: + ; close files + FileClose $0 + FileClose $1 + + ; delete original + Pop $0 + Delete $0.U2D + +FunctionEnd + +;----------------------------------------------------------------------------------- +; Properly compare 2 versions +; syntax: +; ${VersionCompare} "[Version1]" "[Version2]" $var +; output: +; $var=0 Versions are equal +; $var=1 Version1 is newer +; $var=2 Version2 is newer +Function VersionCompare + !define VersionCompare `!insertmacro VersionCompareCall` + + !macro VersionCompareCall _VER1 _VER2 _RESULT + Push `${_VER1}` + Push `${_VER2}` + Call VersionCompare + Pop ${_RESULT} + !macroend + + Exch $1 + Exch + Exch $0 + Exch + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + Push $7 + + begin: + StrCpy $2 -1 + IntOp $2 $2 + 1 + StrCpy $3 $0 1 $2 + StrCmp $3 '' +2 + StrCmp $3 '.' 0 -3 + StrCpy $4 $0 $2 + IntOp $2 $2 + 1 + StrCpy $0 $0 '' $2 + + StrCpy $2 -1 + IntOp $2 $2 + 1 + StrCpy $3 $1 1 $2 + StrCmp $3 '' +2 + StrCmp $3 '.' 0 -3 + StrCpy $5 $1 $2 + IntOp $2 $2 + 1 + StrCpy $1 $1 '' $2 + + StrCmp $4$5 '' equal + + StrCpy $6 -1 + IntOp $6 $6 + 1 + StrCpy $3 $4 1 $6 + StrCmp $3 '0' -2 + StrCmp $3 '' 0 +2 + StrCpy $4 0 + + StrCpy $7 -1 + IntOp $7 $7 + 1 + StrCpy $3 $5 1 $7 + StrCmp $3 '0' -2 + StrCmp $3 '' 0 +2 + StrCpy $5 0 + + StrCmp $4 0 0 +2 + StrCmp $5 0 begin newer2 + StrCmp $5 0 newer1 + IntCmp $6 $7 0 newer1 newer2 + + StrCpy $4 '1$4' + StrCpy $5 '1$5' + IntCmp $4 $5 begin newer2 newer1 + + equal: + StrCpy $0 0 + goto end + newer1: + StrCpy $0 1 + goto end + newer2: + StrCpy $0 2 + + end: + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Exch $0 +FunctionEnd + + +Var OLDVERSION +Var UninstallString + +;----------------------------------------------------------------------------------- +; NSIS Initialize function, determine if we are going to install/upgrade or uninstall +Function .onInit + StrCpy $SHORTCUTS "OpenRCT2" + + SectionSetFlags 0 17 + + ; Starts Setup - let's look for an older version of OpenRCT2 + ReadRegStr $R8 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Version" + + IfErrors ShowWelcomeMessage ShowUpgradeMessage +ShowWelcomeMessage: + ReadRegStr $R8 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "Version" + IfErrors FinishCallback + +ShowUpgradeMessage: + ${VersionCompare} "${APPVERSIONINTERNAL}" "$R8" $R0 + IntCmp $R0 1 WelcomeToSetup VersionsAreEqual InstallerIsOlder +WelcomeToSetup: + ; An older version was found. Let's let the user know there's an upgrade that will take place. + ReadRegStr $OLDVERSION HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "DisplayVersion" + ; Gets the older version then displays it in a message box + MessageBox MB_OK|MB_ICONINFORMATION \ + "Welcome to ${APPNAMEANDVERSION} Setup.$\nThis will allow you to upgrade from version $OLDVERSION." + Goto FinishCallback + +VersionsAreEqual: + ReadRegStr $UninstallString HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenRCT2" "UninstallString" + IfFileExists "$UninstallString" "" FinishCallback + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Setup detected ${APPNAMEANDVERSION} on your system. This is the same version that this program will install.$\nAre you trying to uninstall it?" \ + IDYES DoUninstall IDNO FinishCallback +DoUninstall: ; You have the same version as this installer. This allows you to uninstall. + Exec "$UninstallString" + Quit + +InstallerIsOlder: + ;MessageBox MB_OK|MB_ICONSTOP \ + ; "You have a newer version of ${APPNAME}.$\nSetup will now exit." + ;Quit + MessageBox MB_OK|MB_ICONSTOP \ + "You have a newer version of ${APPNAME}.$\nPlease note downgrading is currently untested." + MessageBox MB_OK|MB_ICONQUESTION \ + "Welcome to ${APPNAMEANDVERSION} Setup.$\nThis will allow you to downgrade from version $OLDVERSION." + Goto FinishCallback + +FinishCallback: + ClearErrors + ; Call CheckProcessorArchitecture + ; Call CheckWindowsVersion +FunctionEnd +; eof diff --git a/distribution/windows/readme.md b/distribution/windows/readme.md new file mode 100644 index 0000000000..edd0c28c17 --- /dev/null +++ b/distribution/windows/readme.md @@ -0,0 +1,6 @@ +# Windows Installer +This directory contains the script and resources for the Windows installer. The installer is created using [Nullsoft Scriptable Install System (NSIS)](http://nsis.sourceforge.net) version v3.0a0+. + +As there is currently only a 32 bit version of OpenRCT2 available, the architecture and windows version checks have been disabled. These will be re-enabled once OpenRCT2 is a stand alone executable. + +Code based on [OpenTTD](http://openttd.org) installer. \ No newline at end of file diff --git a/distribution/windows/top.bmp b/distribution/windows/top.bmp new file mode 100644 index 0000000000..d5cc17ae0d Binary files /dev/null and b/distribution/windows/top.bmp differ diff --git a/distribution/windows/welcome.bmp b/distribution/windows/welcome.bmp new file mode 100644 index 0000000000..6110eba987 Binary files /dev/null and b/distribution/windows/welcome.bmp differ diff --git a/distribution/windows/win32.txt b/distribution/windows/win32.txt new file mode 100644 index 0000000000..ddf41a88ec --- /dev/null +++ b/distribution/windows/win32.txt @@ -0,0 +1,5 @@ +!define APPBITS 32 ; Define number of bits for the architecture +!define EXTRA_VERSION "XP SP3, Vista, 7 and 8.1" +!define APPARCH "win32" ; Define the application architecture +!define BINARY_DIR "${PATH_ROOT}build\Release" +InstallDir "$PROGRAMFILES32\OpenRCT2\" \ No newline at end of file diff --git a/install.sh b/install.sh index e710563731..72cef29197 100755 --- a/install.sh +++ b/install.sh @@ -55,7 +55,7 @@ if [[ `uname` == "Darwin" ]]; then if [[ ! -f $cachedir/$mingw_tar ]]; then wget "https://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Automated Builds/$mingw_tar" --output-document $cachedir/$mingw_tar fi - if [[ ! -d $ming_path ]]; then + if [[ ! -d "$mingw_path" ]]; then pushd /usr/local/ sudo mkdir $mingw_name @@ -84,6 +84,14 @@ if [[ ! -d $cachedir/SDL2-${SDL2_PV} ]]; then tar -xzf SDL2-devel-${SDL2_PV}-mingw.tar.gz popd fi +if [[ ! -f $cachedir/orcalibs.zip ]]; then + wget http://misozmiric.com/ted/openrct2/orcalibs-unix.zip --output-document $cachedir/orcalibs.zip; +fi +if [[ ! -d $cachedir/orcalibs ]]; then + pushd $cachedir + unzip -uaq orcalibs.zip + popd +fi # Apply platform patch mingw_patch=libsdl2-mingw-2.0.3-fix-platform-detection-for-mingw.patch @@ -103,6 +111,9 @@ fi if [[ ! -d /usr/local/cross-tools/i686-w64-mingw32 ]]; then sudo cp -r $cachedir/SDL2-${SDL2_PV}/i686-w64-mingw32 /usr/local/cross-tools/ fi +if [[ ! -d /usr/local/cross-tools/orcalibs ]]; then + sudo cp -r $cachedir/orcalibs /usr/local/cross-tools/ +fi if [[ ! -f $cachedir/i686-w64-mingw32-pkg-config ]]; then # If this fails to work because of newlines, be sure you are running this diff --git a/lib/cutest/CuTest.c b/lib/cutest/CuTest.c new file mode 100644 index 0000000000..8f611991a8 --- /dev/null +++ b/lib/cutest/CuTest.c @@ -0,0 +1,339 @@ +#include +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * CuStr + *-------------------------------------------------------------------------*/ + +char* CuStrAlloc(int size) +{ + char* newStr = (char*) malloc( sizeof(char) * (size) ); + return newStr; +} + +char* CuStrCopy(const char* old) +{ + int len = strlen(old); + char* newStr = CuStrAlloc(len + 1); + strcpy(newStr, old); + return newStr; +} + +/*-------------------------------------------------------------------------* + * CuString + *-------------------------------------------------------------------------*/ + +void CuStringInit(CuString* str) +{ + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; +} + +CuString* CuStringNew(void) +{ + CuString* str = (CuString*) malloc(sizeof(CuString)); + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; + return str; +} + +void CuStringDelete(CuString *str) +{ + if (!str) return; + free(str->buffer); + free(str); +} + +void CuStringResize(CuString* str, int newSize) +{ + str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); + str->size = newSize; +} + +void CuStringAppend(CuString* str, const char* text) +{ + int length; + + if (text == NULL) { + text = "NULL"; + } + + length = strlen(text); + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + str->length += length; + strcat(str->buffer, text); +} + +void CuStringAppendChar(CuString* str, char ch) +{ + char text[2]; + text[0] = ch; + text[1] = '\0'; + CuStringAppend(str, text); +} + +void CuStringAppendFormat(CuString* str, const char* format, ...) +{ + va_list argp; + char buf[HUGE_STRING_LEN]; + va_start(argp, format); + vsprintf(buf, format, argp); + va_end(argp); + CuStringAppend(str, buf); +} + +void CuStringInsert(CuString* str, const char* text, int pos) +{ + int length = strlen(text); + if (pos > str->length) + pos = str->length; + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); + str->length += length; + memcpy(str->buffer + pos, text, length); +} + +/*-------------------------------------------------------------------------* + * CuTest + *-------------------------------------------------------------------------*/ + +void CuTestInit(CuTest* t, const char* name, TestFunction function) +{ + t->name = CuStrCopy(name); + t->failed = 0; + t->ran = 0; + t->message = NULL; + t->function = function; + t->jumpBuf = NULL; +} + +CuTest* CuTestNew(const char* name, TestFunction function) +{ + CuTest* tc = CU_ALLOC(CuTest); + CuTestInit(tc, name, function); + return tc; +} + +void CuTestDelete(CuTest *t) +{ + if (!t) return; + free(t->name); + free(t); +} + +void CuTestRun(CuTest* tc) +{ + jmp_buf buf; + tc->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + tc->ran = 1; + (tc->function)(tc); + } + tc->jumpBuf = 0; +} + +static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) +{ + char buf[HUGE_STRING_LEN]; + + sprintf(buf, "%s:%d: ", file, line); + CuStringInsert(string, buf, 0); + + tc->failed = 1; + tc->message = string->buffer; + if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); +} + +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) +{ + CuString string; + + CuStringInit(&string); + if (message2 != NULL) + { + CuStringAppend(&string, message2); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, message); + CuFailInternal(tc, file, line, &string); +} + +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) +{ + if (condition) return; + CuFail_Line(tc, file, line, NULL, message); +} + +void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const char* expected, const char* actual) +{ + CuString string; + if ((expected == NULL && actual == NULL) || + (expected != NULL && actual != NULL && + strcmp(expected, actual) == 0)) + { + return; + } + + CuStringInit(&string); + if (message != NULL) + { + CuStringAppend(&string, message); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, "expected <"); + CuStringAppend(&string, expected); + CuStringAppend(&string, "> but was <"); + CuStringAppend(&string, actual); + CuStringAppend(&string, ">"); + CuFailInternal(tc, file, line, &string); +} + +void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + int expected, int actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected <%d> but was <%d>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + double expected, double actual, double delta) +{ + char buf[STRING_MAX]; + if (fabs(expected - actual) <= delta) return; + sprintf(buf, "expected <%f> but was <%f>", expected, actual); + + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + void* expected, void* actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + + +/*-------------------------------------------------------------------------* + * CuSuite + *-------------------------------------------------------------------------*/ + +void CuSuiteInit(CuSuite* testSuite) +{ + testSuite->count = 0; + testSuite->failCount = 0; + memset(testSuite->list, 0, sizeof(testSuite->list)); +} + +CuSuite* CuSuiteNew(void) +{ + CuSuite* testSuite = CU_ALLOC(CuSuite); + CuSuiteInit(testSuite); + return testSuite; +} + +void CuSuiteDelete(CuSuite *testSuite) +{ + unsigned int n; + for (n=0; n < MAX_TEST_CASES; n++) + { + if (testSuite->list[n]) + { + CuTestDelete(testSuite->list[n]); + } + } + free(testSuite); + +} + +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) +{ + assert(testSuite->count < MAX_TEST_CASES); + testSuite->list[testSuite->count] = testCase; + testSuite->count++; +} + +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) +{ + int i; + for (i = 0 ; i < testSuite2->count ; ++i) + { + CuTest* testCase = testSuite2->list[i]; + CuSuiteAdd(testSuite, testCase); + } +} + +void CuSuiteRun(CuSuite* testSuite) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuTestRun(testCase); + if (testCase->failed) { testSuite->failCount += 1; } + } +} + +void CuSuiteSummary(CuSuite* testSuite, CuString* summary) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuStringAppend(summary, testCase->failed ? "F" : "."); + } + CuStringAppend(summary, "\n\n"); +} + +void CuSuiteDetails(CuSuite* testSuite, CuString* details) +{ + int i; + int failCount = 0; + + if (testSuite->failCount == 0) + { + int passCount = testSuite->count - testSuite->failCount; + const char* testWord = passCount == 1 ? "test" : "tests"; + CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); + } + else + { + if (testSuite->failCount == 1) + CuStringAppend(details, "There was 1 failure:\n"); + else + CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); + + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + if (testCase->failed) + { + failCount++; + CuStringAppendFormat(details, "%d) %s: %s\n", + failCount, testCase->name, testCase->message); + } + } + CuStringAppend(details, "\n!!!FAILURES!!!\n"); + + CuStringAppendFormat(details, "Runs: %d ", testSuite->count); + CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); + CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); + } +} diff --git a/lib/cutest/CuTest.h b/lib/cutest/CuTest.h new file mode 100644 index 0000000000..8b32773d2b --- /dev/null +++ b/lib/cutest/CuTest.h @@ -0,0 +1,116 @@ +#ifndef CU_TEST_H +#define CU_TEST_H + +#include +#include + +#define CUTEST_VERSION "CuTest 1.5" + +/* CuString */ + +char* CuStrAlloc(int size); +char* CuStrCopy(const char* old); + +#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) + +#define HUGE_STRING_LEN 8192 +#define STRING_MAX 256 +#define STRING_INC 256 + +typedef struct +{ + int length; + int size; + char* buffer; +} CuString; + +void CuStringInit(CuString* str); +CuString* CuStringNew(void); +void CuStringRead(CuString* str, const char* path); +void CuStringAppend(CuString* str, const char* text); +void CuStringAppendChar(CuString* str, char ch); +void CuStringAppendFormat(CuString* str, const char* format, ...); +void CuStringInsert(CuString* str, const char* text, int pos); +void CuStringResize(CuString* str, int newSize); +void CuStringDelete(CuString* str); + +/* CuTest */ + +typedef struct CuTest CuTest; + +typedef void (*TestFunction)(CuTest *); + +struct CuTest +{ + char* name; + TestFunction function; + int failed; + int ran; + const char* message; + jmp_buf *jumpBuf; +}; + +void CuTestInit(CuTest* t, const char* name, TestFunction function); +CuTest* CuTestNew(const char* name, TestFunction function); +void CuTestRun(CuTest* tc); +void CuTestDelete(CuTest *t); + +/* Internal versions of assert functions -- use the public versions */ +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); +void CuAssertStrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const char* expected, const char* actual); +void CuAssertIntEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + int expected, int actual); +void CuAssertDblEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + double expected, double actual, double delta); +void CuAssertPtrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + void* expected, void* actual); + +/* public assert functions */ + +#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) +#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) +#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) + +#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) +#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) +#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) + +#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) +#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) + +/* CuSuite */ + +#define MAX_TEST_CASES 1024 + +#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) + +typedef struct +{ + int count; + CuTest* list[MAX_TEST_CASES]; + int failCount; + +} CuSuite; + + +void CuSuiteInit(CuSuite* testSuite); +CuSuite* CuSuiteNew(void); +void CuSuiteDelete(CuSuite *testSuite); +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); +void CuSuiteRun(CuSuite* testSuite); +void CuSuiteSummary(CuSuite* testSuite, CuString* summary); +void CuSuiteDetails(CuSuite* testSuite, CuString* details); + +#endif /* CU_TEST_H */ diff --git a/lib/cutest/license.txt b/lib/cutest/license.txt new file mode 100644 index 0000000000..fd81689df4 --- /dev/null +++ b/lib/cutest/license.txt @@ -0,0 +1,38 @@ +NOTE + +The license is based on the zlib/libpng license. For more details see +http://www.opensource.org/licenses/zlib-license.html. The intent of the +license is to: + +- keep the license as simple as possible +- encourage the use of CuTest in both free and commercial applications + and libraries +- keep the source code together +- give credit to the CuTest contributors for their work + +If you ship CuTest in source form with your source distribution, the +following license document must be included with it in unaltered form. +If you find CuTest useful we would like to hear about it. + +LICENSE + +Copyright (c) 2003 Asim Jalis + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. diff --git a/pre-build.ps1 b/pre-build.ps1 new file mode 100644 index 0000000000..8dadd76d26 --- /dev/null +++ b/pre-build.ps1 @@ -0,0 +1,15 @@ +$path = Split-Path $Script:MyInvocation.MyCommand.Path +$zip = $path+'\lib\orcalibs.zip' +$libs = $path+'\lib' +$libcurl = Test-Path $path\lib\libcurl\ +$jansson = Test-Path $path\lib\jansson\ +$sdl = Test-Path $path\lib\sdl\ +if (!$libcurl -or !$jansson -or !$sdl) { + Invoke-WebRequest http://misozmiric.com/ted/openrct2/orcalibs-vs.zip -OutFile $path\lib\orcalibs.zip + rm $path\lib\libcurl -r -Force -ErrorAction SilentlyContinue + rm $path\lib\jansson -r -Force -ErrorAction SilentlyContinue + rm $path\lib\sdl -r -Force -ErrorAction SilentlyContinue + [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') > $null + [System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $libs) + rm $path\lib\orcalibs.zip -Force -ErrorAction SilentlyContinue +} diff --git a/projects/language/language.vcxproj b/projects/language/language.vcxproj new file mode 100644 index 0000000000..b37e1107f4 --- /dev/null +++ b/projects/language/language.vcxproj @@ -0,0 +1,125 @@ + + + + + Debug + Win32 + + + Release with Tests + Win32 + + + Release + Win32 + + + + {0468FC1E-5881-4DB9-9DDE-1892290B31D9} + language + + + + Utility + true + v120 + MultiByte + + + Utility + false + v120 + true + MultiByte + + + Utility + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + + + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + + + $(SolutionDir)..\build\Release\ + $(SolutionDir)..\obj\$(ProjectName)\Release\ + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + xcopy /Y "$(SolutionDir)\..\Data\Language\*.*" "$(TargetDir)\Data\Language\" + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + xcopy /Y "$(SolutionDir)\..\Data\Language\*.*" "$(TargetDir)\Data\Language\" + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/language/language.vcxproj.filters b/projects/language/language.vcxproj.filters new file mode 100644 index 0000000000..0c3b4d393c --- /dev/null +++ b/projects/language/language.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {96ec0470-f3e0-443e-8715-171ad8676bb6} + + + + + Resource Files\Language + + + Resource Files\Language + + + Resource Files\Language + + + Resource Files\Language + + + Resource Files\Language + + + Resource Files\Language + + + Resource Files\Language + + + Resource Files\Language + + + Resource Files\Language + + + \ No newline at end of file diff --git a/projects/libs/libs.vcxproj b/projects/libs/libs.vcxproj new file mode 100644 index 0000000000..c1ae556f71 --- /dev/null +++ b/projects/libs/libs.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Release with Tests + Win32 + + + Release + Win32 + + + + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB} + libs + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + ..\..\lib\openssl\include;$(IncludePath) + + + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;$(IncludePath) + ..\..\lib\libcurl\lib;$(LibraryPath) + + + $(SolutionDir)..\build\Release\ + $(SolutionDir)..\obj\$(ProjectName)\Release\ + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;$(IncludePath) + ..\..\lib\libcurl\lib;$(LibraryPath) + + + + Level3 + Disabled + true + MultiThreaded + 1Byte + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;NS_ENABLE_THREADS;NS_ENABLE_SSL;DISABLE_MD5;%(PreprocessorDefinitions) + + + true + + + + + Level3 + MaxSpeed + true + true + true + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;NS_ENABLE_THREADS;NS_ENABLE_SSL;DISABLE_MD5;%(PreprocessorDefinitions) + MultiThreaded + 1Byte + + + + + true + true + true + + + libcurl.lib;Ws2_32.lib;%(AdditionalDependencies) + + + Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" + + + + + Level3 + MaxSpeed + true + true + true + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;NS_ENABLE_THREADS;NS_ENABLE_SSL;DISABLE_MD5;%(PreprocessorDefinitions) + MultiThreaded + 1Byte + + + + + true + true + true + + + libcurl.lib;Ws2_32.lib;%(AdditionalDependencies) + + + Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" + + + + + TurnOffAllWarnings + TurnOffAllWarnings + TurnOffAllWarnings + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/libs/libs.vcxproj.filters b/projects/libs/libs.vcxproj.filters new file mode 100644 index 0000000000..feaf95a9ee --- /dev/null +++ b/projects/libs/libs.vcxproj.filters @@ -0,0 +1,124 @@ + + + + + {f28d7721-061f-44b8-bbd5-42dc9483b387} + + + {69f22202-b887-4e7c-bf7c-eb581571398d} + + + {45966214-8043-431c-8eb3-920c00bf749d} + + + {7f953e55-d294-4158-b309-67f41fa82760} + + + {7b46a2d6-1095-4e7a-b98b-006b832ef7a1} + + + {16ee6cb9-307a-4e8a-8261-a69d91b17739} + + + {92e56bd7-37be-465c-9212-3b6cfb8cf7c9} + + + + + argparse + + + libspeex + + + lodepng + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + cutest + + + + + argparse + + + libspeex + + + libspeex + + + libspeex + + + libspeex + + + libspeex\speex + + + libspeex\speex + + + lodepng + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + jansson + + + + \ No newline at end of file diff --git a/projects/openrct2.sln b/projects/openrct2.sln index f176b7813f..67248e41b4 100644 --- a/projects/openrct2.sln +++ b/projects/openrct2.sln @@ -1,20 +1,42 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.30110.0 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openrct2", "openrct2.vcxproj", "{D24D94F6-2A74-480C-B512-629C306CE92F}" + ProjectSection(ProjectDependencies) = postProject + {0468FC1E-5881-4DB9-9DDE-1892290B31D9} = {0468FC1E-5881-4DB9-9DDE-1892290B31D9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "language", "language\language.vcxproj", "{0468FC1E-5881-4DB9-9DDE-1892290B31D9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libs", "libs\libs.vcxproj", "{074DC930-05C6-4B7F-B5DD-DD237E6E44DB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Release with Tests|Win32 = Release with Tests|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D24D94F6-2A74-480C-B512-629C306CE92F}.Debug|Win32.ActiveCfg = Debug|Win32 {D24D94F6-2A74-480C-B512-629C306CE92F}.Debug|Win32.Build.0 = Debug|Win32 + {D24D94F6-2A74-480C-B512-629C306CE92F}.Release with Tests|Win32.ActiveCfg = Release with Tests|Win32 + {D24D94F6-2A74-480C-B512-629C306CE92F}.Release with Tests|Win32.Build.0 = Release with Tests|Win32 {D24D94F6-2A74-480C-B512-629C306CE92F}.Release|Win32.ActiveCfg = Release|Win32 {D24D94F6-2A74-480C-B512-629C306CE92F}.Release|Win32.Build.0 = Release|Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9}.Debug|Win32.ActiveCfg = Debug|Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9}.Debug|Win32.Build.0 = Debug|Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9}.Release with Tests|Win32.ActiveCfg = Release with Tests|Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9}.Release with Tests|Win32.Build.0 = Release with Tests|Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9}.Release|Win32.ActiveCfg = Release|Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9}.Release|Win32.Build.0 = Release|Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Debug|Win32.ActiveCfg = Debug|Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Debug|Win32.Build.0 = Debug|Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Release with Tests|Win32.ActiveCfg = Release with Tests|Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Release with Tests|Win32.Build.0 = Release with Tests|Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Release|Win32.ActiveCfg = Release|Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index bb257a0b4a..3e8b0c411a 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -2,6 +2,7 @@ + @@ -9,46 +10,26 @@ Debug Win32 + + Release with Tests + Win32 + Release Win32 + - - - - - - - - - - - - - - - - - - - - - - TurnOffAllWarnings - - - TurnOffAllWarnings - - + + @@ -60,6 +41,13 @@ + + + + + + + @@ -79,6 +67,8 @@ + + @@ -86,20 +76,24 @@ - + + + + + + - @@ -115,16 +109,18 @@ - - + + + + @@ -147,22 +143,35 @@ + + + + + + + + + + + + + @@ -179,6 +188,13 @@ + + + + + + + @@ -197,37 +213,52 @@ + + - + + + + + - - + + + + + + + + + + {074dc930-05c6-4b7f-b5dd-dd237e6e44db} + {D24D94F6-2A74-480C-B512-629C306CE92F} @@ -248,6 +279,13 @@ true MultiByte + + DynamicLibrary + false + v120 + true + MultiByte + @@ -257,18 +295,30 @@ + + + $(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(SolutionDir)..\libspeex;$(IncludePath) $(SolutionDir)..\sdl\lib\x86;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ - $(SolutionDir)..\obj\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(IncludePath) - $(SolutionDir)..\lib\sdl\lib\x86;$(LibraryPath) + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(IncludePath) + $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ - $(SolutionDir)..\obj\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + + + + + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(IncludePath) + $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) + $(SolutionDir)..\build\Release\ + $(SolutionDir)..\obj\$(ProjectName)\Release\ + @@ -277,11 +327,16 @@ true 1Byte _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions) + MultiThreaded true winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + + "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" +xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + @@ -297,18 +352,69 @@ false - _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;%(PreprocessorDefinitions) $(IntDir)fake\%(RelativeDir) + true true true true winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + /ignore:4099 %(AdditionalOptions) - xcopy /Y "$(ProjectDir)\..\Data\Language\*.*" "$(TargetDir)\Data\Language\" + "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" +xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + Build g2.dat and copy the Data directory. + + + + + + + + + + + + Level3 + Disabled + true + true + + + MultiThreaded + 1Byte + 4013 + + + false + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;ENABLE_TESTS;%(PreprocessorDefinitions) + $(IntDir)fake\%(RelativeDir) + true + + + true + true + true + winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + /ignore:4099 %(AdditionalOptions) + + + "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" +xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + Build g2.dat and copy the Data directory. + + + + + + + + + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 824a4edcc2..fad60aeef3 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -5,27 +5,12 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - {29bd2abb-0a50-4c58-9031-bee3f966b249} - - - {e9219aff-1bb5-4065-8204-427a97344a43} - - - {3c824fc4-8242-4127-a4b4-248435ff9058} - {4c8348c7-dfe9-4368-9d87-29733fe5950a} {8e15cd5b-d7a7-4bda-a58a-e1158ad6ffb4} - - {ee2e3a6f-1209-407b-8000-a6a4b88d28d9} - - - {b344ca0f-b412-4924-be08-54bb6f83c3dd} - {8a9b8831-4ba9-4104-b13f-949981e10c22} @@ -53,49 +38,29 @@ {81716f5d-b396-4a82-a450-76fee56d982b} - - {209155b8-2f61-4e25-ab86-c8aa36357abd} - {51e38783-5334-464c-8f90-61d725dc8013} - - {7e9587b2-333f-42ca-8a56-b77070828b17} + + {ae88ed08-902b-4167-a78c-9b521ce67749} + + + {9b842d7a-225e-4ba9-807d-1cb6ebacbdd0} + + + {73238872-312d-437f-8497-7cb66466d835} + + + {c6b9c169-ff2a-41df-9b1c-47d15763c3e2} Resource Files - - - - Source\Data\Language - - - Source\Data\Language - - - Source\Data\Language - - - Source\Data\Language - - - Source\Data\Language - - - Source\Data\Language - - - Source\Data\Language - - - Source\Data\Language - - - Source\Data\Language - + + Resource Files + @@ -170,9 +135,6 @@ Source\Windows - - Source\Windows - Source\Windows @@ -254,9 +216,6 @@ Source\Localisation - - Source\Platform - Source\Ride @@ -278,9 +237,6 @@ Source\Util - - Source - Source @@ -380,79 +336,54 @@ Source\Drawing - - - - - - - Source Source - - Libraries\argparse - - - Source\World - Source\World Source\Windows - Source\Windows Source\Windows - Source\Windows - Source\Windows Source\Windows - Source\Ride - Source\Windows - Source\Interface Source\Interface - Source\World - Source - - - Source - Source\Windows @@ -462,14 +393,9 @@ Source\Windows - - Source\Windows - - Source\Localisation - Source\Windows @@ -479,6 +405,81 @@ Source\Windows + + Source\World + + + Source\World + + + Source\Windows + + + Source\Windows + + + Source\Ride + + + Source + + + Source\Windows + + + Source + + + Source\Windows + + + Source\World + + + Source\World + + + Source + + + Source\Windows + + + Source + + + Source\Windows + + + Source\Interface + + + Source\Network + + + Source\Network + + + Source\Interface + + + Source\Windows + + + Test + + + Test\Management + + + Test\Ride + + + Source\Windows + + + Source\Windows + @@ -535,9 +536,6 @@ Source\Windows - - Source\Windows - Source\Windows @@ -550,9 +548,6 @@ Source\Localisation - - Source\Platform - Source\Ride @@ -634,27 +629,6 @@ Source\Localisation - - Libraries\lodepng - - - Libraries\libspeex - - - Libraries\libspeex - - - Libraries\libspeex - - - Libraries\libspeex - - - Libraries\libspeex\speex - - - Libraries\libspeex\speex - Source\Peep @@ -670,9 +644,6 @@ Source - - Libraries\argparse - Source\World @@ -688,8 +659,50 @@ Source - + Source + + Source\World + + + Source\World + + + Source\Ride + + + Source\World + + + Source\World + + + Source\World + + + Source\World + + + Source\Interface + + + Source\Network + + + Source\Network + + + Source\Interface + + + Test + + + Test\Management + + + Test\Ride + \ No newline at end of file diff --git a/projects/openrct2.vcxproj.user b/projects/openrct2.vcxproj.user index d08f3ad23c..33fff921b3 100644 --- a/projects/openrct2.vcxproj.user +++ b/projects/openrct2.vcxproj.user @@ -1,18 +1,20 @@  - - false - - - $(TargetDir)\openrct2.exe - WindowsLocalDebugger - $(TargetDir) - - $(TargetDir)\openrct2.exe $(TargetDir) WindowsLocalDebugger + $(TargetDir)\openrct2.exe + + $(TargetDir) + WindowsLocalDebugger + $(TargetDir)\openrct2.exe + + + + + false + \ No newline at end of file diff --git a/readme.md b/readme.md index 0b188a87c6..3b5b0c0d05 100644 --- a/readme.md +++ b/readme.md @@ -14,7 +14,7 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original - 1.1 - [Background](#11-background) - 1.2 - [Decompiling the game](#12-decompiling-the-game) - 1.3 - [Progress](#13-progress) - - 1.4 - [Aim](#14-aim) + - 1.4 - [Aim](#14-aim) - 2 - [Downloading the game / Building the source code](#2-building-the-source-code) - 2.1 - [Prerequisites](#21-prerequisites) - 2.2 - [Compiling and running](#22-compiling-and-running) @@ -23,12 +23,13 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original - 3.2 - [Naming of procedures and variables](#32-naming-of-procedures-and-variables) - 3.3 - [Cleaning and documenting the source code](#33-cleaning-and-documenting-the-source-code) - 3.4 - [Implementing new features / fixing bugs](#34-implementing-new-features--fixing-bugs) + - 3.5 - [Translation](#35-translation) - 4 - [Licence](#4-license) # 1 Introduction ## 1.1 Background -**OpenRCT2** is an attempt to decompile RollerCoaster Tycoon 2 into C. RollerCoaster Tycoon 2 was originally written in MASM and Visual C++ where functions related to interfacing with the operating system were written in C (supposedly 1%), with the rest of the game being written in pure x86 assembly. For an example of this method, OpenTTD was formed through a similar procedure; the original game, Transport Tycoon Deluxe, was decompiled into C which allowed for the addition of thousands of features to the game. RollerCoaster Tycoon 2 uses the third version of Chris Sawyer's engine, which shares some code with Transport Tycoon. This is reflected in the usage of OpenTTD 0.1 code such as the windowing system and graphics rendering. While the version of the engine used in Chris Sawyer's Locomotion is newer, OpenRCT2 is currently targeting the RollerCoaster Tycoon 2 engine to ease the decompilation process. +**OpenRCT2** is an attempt to decompile RollerCoaster Tycoon 2 into C. RollerCoaster Tycoon 2 was originally written in MASM and Visual C++ where functions related to interfacing with the operating system were written in C (supposedly 1%), with the rest of the game being written in pure x86 assembly. For an example of this method, OpenTTD was formed through a similar procedure; the original game, Transport Tycoon Deluxe, was decompiled into C which allowed for the addition of thousands of features to the game. RollerCoaster Tycoon 2 uses the third version of Chris Sawyer's engine, which shares some code with Transport Tycoon. This is reflected in the usage of OpenTTD 0.1 code such as the windowing system and graphics rendering. While the version of the engine used in Chris Sawyer's Locomotion is newer, OpenRCT2 is currently targeting the RollerCoaster Tycoon 2 engine to ease the decompilation process. ## 1.2 Decompiling the game In order to decompile the game gradually without introducing new bugs, each procedure in RollerCoaster Tycoon 2 is to be re-written in C on an individual basis. To test the accuracy of the re-written procedures, the decompiled C procedures are compiled into a DLL (*openrct2.dll*) which exports an entry procedure mimicking the WinMain function in RollerCoaster Tycoon 2. The original executable *rct2.exe* has been patched so that *openrct2.dll* and WinMain are in the DLL import table and the WinMain export procedure in *openrct2.dll* is called at the start of the WinMain procedure in *rct2.exe* before returning. With this system implemented, starting rct2.exe calls the new DLL as part of its initialization; the DLL can then run all the decompiled code whilst still being able to read / write to the *rct2.exe* memory model and run *rct2.exe* procedures. @@ -41,27 +42,34 @@ Currently, the windowing system, graphics rendering and basic game loop are bein As of 16th August 2014, various UI improvements have already been made, settings are now stored in a local INI file. More drawing functions have now been decompiled but still remain cryptic C, much of the game management have been decompiled (e.g. peep generation, awards, cash out) and almost half of the windows. A rough estimate based on number of functions in the original game and number of functions now in C tells us that the project is approximately 25% complete of its target goal of having the game run on 100% C code. More information can be found in [changes to original game](https://github.com/IntelOrca/OpenRCT2/wiki/Changes-to-original-game) and [window progress](https://github.com/IntelOrca/OpenRCT2/wiki/Window-progress). ## 1.4 Aim -The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-platform support, new features, and new gameplay can be added in a similar fashion to OpenTTD. With the addition of SDL2, the game can already be run in a resizeable window (which was not possible originally). Once the game has been fully decompiled, additional gameplay features, gameplay tweaks, and improvements can be introduced. The following is only a brief, non-exhaustive list of the possibilities - there is much more possible: +The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-platform support, new features, and new gameplay can be added in a similar fashion to OpenTTD. With the addition of SDL2, the game can already be run in a resizeable window (which was not possible originally). Once the game has been fully decompiled, additional gameplay features, gameplay tweaks, and improvements can be introduced. The following is only a brief, non-exhaustive list of the possibilities - there are many more: + - Improved peep path-finding - Increased window / ride / object / map / construction limits - More sandbox-friendly gameplay - Editing available objects - Improved title sequence -- Re-introduction of RollerCoaster Tycoon 1 mechanics - - Shuttle Loop compatibility - - Have Fun! objective - - Finish building five coasters objective - - Using the mountain tool during the game +- Translation into more languages +- Re-introduction of RollerCoaster Tycoon 1 mechanics: + - Shuttle Loop compatibility + - Have Fun! objective + - Finish building five coasters objective + - Using the mountain tool during the game # 2 Downloading the game / Building the source code -A third-party offers [downloadable precompiled builds](https://openrct2.com/download). However, building the project is always recommended. +A couple of third parties offer downloadable precompiled builds. However, building the project is always recommended + +[OpenRCT2.com](https://openrct2.com/download) +[OpenRCT.net](https://openrct.net/builds.php) + +There is also a Launcher available from [OpenRCT.net](https://openrct.net/download) that will automatically update your build so that you always have the current version as they are released. ## 2.1 Prerequisites ### Windows: -- Windows XP / Vista / 7 / 8 +- Windows XP / Vista / 7 / 8 / 10 - RollerCoaster Tycoon 2 -- Visual Studio 2013 (paid) / [Visual Studio Express 2013](http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop) (free) +- Visual Studio 2013 (Professional / [Community](http://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) / [Express for Windows Desktop](http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop)) - [SDL2 development library for Visual C++](http://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip). ### Max OS X: @@ -120,5 +128,17 @@ In general, small changes that improve code quality and make it easier to reason ## 3.4 Implementing new features / fixing bugs While decompilation is an ongoing process, this does not prohibit changes being made to the game. New features or bugfixes can be added, with caution, if the underlying code has been decompiled. When implementing these changes, ensure that comments are added to clearly identify where code has been intentionally changed so that it functions differently to the original game; this is essential to ensuring all research from reverse-engineering can still be applied. +## 3.5 Translation +Translations are in progress for German, Dutch, French, Hungarian, Polish, Spanish, Swedish, Italian, and more. You can translate the game into other languages by editing the language files in the data directory. Please join discussions and submit pull requests to https://github.com/OpenRCT2/Localisation. + # 4 License **OpenRCT2** is licensed under the GNU General Public License version 3. + +# 5 More information +- [GitHub](https://github.com/IntelOrca/OpenRCT2) +- [Facebook](https://www.facebook.com/OpenRCT2) +- [Automated builds](https://openrct2.com/download) +- [Secondary site for automated builds](https://openrct.net/builds.php) +- [Launcher that keeps your copy up-to-date](https://openrct.net/download) +- [rct2 subreddit](http://www.reddit.com/r/rct/) +- [openrct2 subreddit](http://www.reddit.com/r/openrct2) diff --git a/resources/g2/0.png b/resources/g2/0.png new file mode 100644 index 0000000000..f99b17660d Binary files /dev/null and b/resources/g2/0.png differ diff --git a/resources/g2/1.png b/resources/g2/1.png new file mode 100644 index 0000000000..75686931c2 Binary files /dev/null and b/resources/g2/1.png differ diff --git a/resources/g2/10.png b/resources/g2/10.png new file mode 100644 index 0000000000..296f07c150 Binary files /dev/null and b/resources/g2/10.png differ diff --git a/resources/g2/11.png b/resources/g2/11.png new file mode 100644 index 0000000000..4d7afd5519 Binary files /dev/null and b/resources/g2/11.png differ diff --git a/resources/g2/12.png b/resources/g2/12.png new file mode 100644 index 0000000000..6c23464669 Binary files /dev/null and b/resources/g2/12.png differ diff --git a/resources/g2/13.png b/resources/g2/13.png new file mode 100644 index 0000000000..17b58d28c4 Binary files /dev/null and b/resources/g2/13.png differ diff --git a/resources/g2/14.png b/resources/g2/14.png new file mode 100644 index 0000000000..39d0aae679 Binary files /dev/null and b/resources/g2/14.png differ diff --git a/resources/g2/15.png b/resources/g2/15.png new file mode 100644 index 0000000000..efbe194fa8 Binary files /dev/null and b/resources/g2/15.png differ diff --git a/resources/g2/16.png b/resources/g2/16.png new file mode 100644 index 0000000000..da44df3978 Binary files /dev/null and b/resources/g2/16.png differ diff --git a/resources/g2/17.png b/resources/g2/17.png new file mode 100644 index 0000000000..e81026a205 Binary files /dev/null and b/resources/g2/17.png differ diff --git a/resources/g2/18.png b/resources/g2/18.png new file mode 100644 index 0000000000..3c09112bcb Binary files /dev/null and b/resources/g2/18.png differ diff --git a/resources/g2/19.png b/resources/g2/19.png new file mode 100644 index 0000000000..b93d530db1 Binary files /dev/null and b/resources/g2/19.png differ diff --git a/resources/g2/2.png b/resources/g2/2.png new file mode 100644 index 0000000000..674702e550 Binary files /dev/null and b/resources/g2/2.png differ diff --git a/resources/g2/20.png b/resources/g2/20.png new file mode 100644 index 0000000000..911a96b365 Binary files /dev/null and b/resources/g2/20.png differ diff --git a/resources/g2/21.png b/resources/g2/21.png new file mode 100644 index 0000000000..3ef302396b Binary files /dev/null and b/resources/g2/21.png differ diff --git a/resources/g2/22.png b/resources/g2/22.png new file mode 100644 index 0000000000..13c5deff4f Binary files /dev/null and b/resources/g2/22.png differ diff --git a/resources/g2/23.png b/resources/g2/23.png new file mode 100644 index 0000000000..fe36ece361 Binary files /dev/null and b/resources/g2/23.png differ diff --git a/resources/g2/24.png b/resources/g2/24.png new file mode 100644 index 0000000000..d65776eb76 Binary files /dev/null and b/resources/g2/24.png differ diff --git a/resources/g2/25.png b/resources/g2/25.png new file mode 100644 index 0000000000..55b8ae3297 Binary files /dev/null and b/resources/g2/25.png differ diff --git a/resources/g2/26.png b/resources/g2/26.png new file mode 100644 index 0000000000..c22e6db171 Binary files /dev/null and b/resources/g2/26.png differ diff --git a/resources/g2/27.png b/resources/g2/27.png new file mode 100644 index 0000000000..bde9cde380 Binary files /dev/null and b/resources/g2/27.png differ diff --git a/resources/g2/28.png b/resources/g2/28.png new file mode 100644 index 0000000000..d98274d407 Binary files /dev/null and b/resources/g2/28.png differ diff --git a/resources/g2/3.png b/resources/g2/3.png new file mode 100644 index 0000000000..20432f67df Binary files /dev/null and b/resources/g2/3.png differ diff --git a/resources/g2/4.png b/resources/g2/4.png new file mode 100644 index 0000000000..24395cc1b7 Binary files /dev/null and b/resources/g2/4.png differ diff --git a/resources/g2/5.png b/resources/g2/5.png new file mode 100644 index 0000000000..05c0c42984 Binary files /dev/null and b/resources/g2/5.png differ diff --git a/resources/g2/6.png b/resources/g2/6.png new file mode 100644 index 0000000000..a441a6c73d Binary files /dev/null and b/resources/g2/6.png differ diff --git a/resources/g2/7.png b/resources/g2/7.png new file mode 100644 index 0000000000..205d3c50a4 Binary files /dev/null and b/resources/g2/7.png differ diff --git a/resources/g2/8.png b/resources/g2/8.png new file mode 100644 index 0000000000..283c1fc325 Binary files /dev/null and b/resources/g2/8.png differ diff --git a/resources/g2/9.png b/resources/g2/9.png new file mode 100644 index 0000000000..750be39876 Binary files /dev/null and b/resources/g2/9.png differ diff --git a/resources/g2/empty.png b/resources/g2/empty.png new file mode 100644 index 0000000000..205d3c50a4 Binary files /dev/null and b/resources/g2/empty.png differ diff --git a/resources/logo/icon.ico b/resources/logo/icon.ico new file mode 100644 index 0000000000..d09fe11e03 Binary files /dev/null and b/resources/logo/icon.ico differ diff --git a/resources/logo/icon_flag.svg b/resources/logo/icon_flag.svg new file mode 100644 index 0000000000..f84ce891ec --- /dev/null +++ b/resources/logo/icon_flag.svg @@ -0,0 +1,1408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/logo/icon_noflag.svg b/resources/logo/icon_noflag.svg new file mode 100644 index 0000000000..907c9f88fe --- /dev/null +++ b/resources/logo/icon_noflag.svg @@ -0,0 +1,1338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/logo/icon_x1024.png b/resources/logo/icon_x1024.png new file mode 100644 index 0000000000..98205aab94 Binary files /dev/null and b/resources/logo/icon_x1024.png differ diff --git a/resources/logo/icon_x128.png b/resources/logo/icon_x128.png new file mode 100644 index 0000000000..3202bbf801 Binary files /dev/null and b/resources/logo/icon_x128.png differ diff --git a/resources/logo/icon_x16.png b/resources/logo/icon_x16.png new file mode 100644 index 0000000000..66e94a9dee Binary files /dev/null and b/resources/logo/icon_x16.png differ diff --git a/resources/logo/icon_x2048.png b/resources/logo/icon_x2048.png new file mode 100644 index 0000000000..a4610a7cb2 Binary files /dev/null and b/resources/logo/icon_x2048.png differ diff --git a/resources/logo/icon_x256.png b/resources/logo/icon_x256.png new file mode 100644 index 0000000000..fc1e5932ad Binary files /dev/null and b/resources/logo/icon_x256.png differ diff --git a/resources/logo/icon_x32.png b/resources/logo/icon_x32.png new file mode 100644 index 0000000000..eacc66b5eb Binary files /dev/null and b/resources/logo/icon_x32.png differ diff --git a/resources/logo/icon_x4.png b/resources/logo/icon_x4.png new file mode 100644 index 0000000000..08fdf34f6d Binary files /dev/null and b/resources/logo/icon_x4.png differ diff --git a/resources/logo/icon_x512.png b/resources/logo/icon_x512.png new file mode 100644 index 0000000000..c8a0d4392e Binary files /dev/null and b/resources/logo/icon_x512.png differ diff --git a/resources/logo/icon_x64.png b/resources/logo/icon_x64.png new file mode 100644 index 0000000000..907fab8f64 Binary files /dev/null and b/resources/logo/icon_x64.png differ diff --git a/resources/logo/icon_x8.png b/resources/logo/icon_x8.png new file mode 100644 index 0000000000..ad0e979458 Binary files /dev/null and b/resources/logo/icon_x8.png differ diff --git a/resources/logo/makeico.linq b/resources/logo/makeico.linq new file mode 100644 index 0000000000..247c87eb0b --- /dev/null +++ b/resources/logo/makeico.linq @@ -0,0 +1,44 @@ + + System.Drawing + System.Drawing.Imaging + + +string inputDirectory = @"C:\Users\Ted\Documents\Programming\Projects\Hacking\OpenRCT2\resources\logo"; +string outputPath = @"C:\Users\Ted\Documents\Programming\Projects\Hacking\OpenRCT2\resources\logo\icon.ico"; +int numImages = 7; +using (FileStream fs = new FileStream(outputPath, FileMode.Create)) { + BinaryWriter bw = new BinaryWriter(fs); + bw.Write((short)0); + bw.Write((short)1); + bw.Write((short)numImages); + + int dataStartOffset = 6 + (numImages * 16); + + using (MemoryStream dataStream = new MemoryStream()) { + int size = 256; + for (int i = 0; i < numImages; i++) { + bw.Write((byte)(size == 256 ? 0 : size)); + bw.Write((byte)(size == 256 ? 0 : size)); + bw.Write((byte)0); + bw.Write((byte)0); + bw.Write((short)0); + bw.Write((short)32); + + int dataOffset = (int)dataStream.Position; + int dataLength; + + string inputImagePath = Path.Combine(inputDirectory, "icon_x" + size + ".png"); + using (Image image = Image.FromFile(inputImagePath)) + image.Save(dataStream, ImageFormat.Png); + + dataLength = (int)dataStream.Position - dataOffset; + dataOffset += dataStartOffset; + + bw.Write(dataLength); + bw.Write(dataOffset); + + size /= 2; + } + bw.Write(dataStream.ToArray()); + } +} \ No newline at end of file diff --git a/run.bat b/run.bat new file mode 100644 index 0000000000..6f18175b9f --- /dev/null +++ b/run.bat @@ -0,0 +1 @@ +.\build\Release\openrct2.exe %* \ No newline at end of file diff --git a/src/addresses.h b/src/addresses.h index 6db1e7bd32..e74cede5f2 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -21,7 +21,9 @@ #ifndef _ADDRESSES_H_ #define _ADDRESSES_H_ +#ifdef _MSC_VER #pragma warning(disable : 4731) +#endif #define RCT2_ADDRESS(address, type) ((type*)(address)) #define RCT2_GLOBAL(address, type) (*((type*)(address))) @@ -56,7 +58,7 @@ #define RCT2_ADDRESS_RIDE_PROPERTIES 0x00997C9D #define RCT2_ADDRESS_LAND_TOOL_SIZE 0x009A9800 #define RCT2_ADDRESS_SAVE_PROMPT_MODE 0x009A9802 - +#define RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS 0x009A9804 #define RCT2_ADDRESS_MAP_TOOLTIP_ARGS 0x009A9808 // #define RCT2_ADDRESS_SCENARIO_LIST 0x009A9FF4 @@ -67,9 +69,15 @@ #define RCT2_ADDRESS_DSOUND_GUID 0x009AAC5D #define RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER 0x009AAC6E +// When all sounds reversed replace with gConfigSound.ride_music #define RCT2_ADDRESS_CONFIG_MUSIC 0x009AAC72 #define RCT2_ADDRESS_CONFIG_FLAGS 0x009AAC74 + +// MAX vehicle sounds not used anymore +#define RCT2_ADDRESS_CONFIG_MAX_VEHICLE_SOUNDS 0x009AAC75 + +#define RCT2_ADDRESS_CONFIG_MAX_NO_SOUNDS 0x009AAC76 #define RCT2_ADDRESS_CONFIG_SOUND_QUALITY 0x009AAC77 #define RCT2_ADDRESS_CONFIG_METRIC 0x009AAC78 #define RCT2_ADDRESS_CONFIG_TEMPERATURE 0x009AAC79 @@ -121,9 +129,30 @@ #define RCT2_ADDRESS_RUN_INTRO_TICK_PART 0x009AC319 +// 0 = none, 255 = load file, 254 = anything else +#define RCT2_ADDRESS_ERROR_TYPE 0x009AC31B +#define RCT2_ADDRESS_ERROR_STRING_ID 0x009AC31C + +#define RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS 0x009AC861 + #define RCT2_ADDRESS_RIDE_ENTRIES 0x009ACFA4 + + +#define RCT2_ADDRESS_SMALL_SCENERY_ENTRIES 0x009AD1A4 +#define RCT2_ADDRESS_LARGE_SCENERY_ENTRIES 0x009AD594 +#define RCT2_ADDRESS_WALL_SCENERY_ENTRIES 0x009AD794 +#define RCT2_ADDRESS_BANNER_SCENERY_ENTRIES 0x009AD994 +#define RCT2_ADDRESS_PATH_TYPES 0x009ADA14 +#define RCT2_ADDRESS_PATH_BIT_SCENERY_ENTRIES 0x009ADA54 +#define RCT2_ADDRESS_SCENERY_SET_ENTRIES 0x009ADA90 + #define RCT2_ADDRESS_INSTALLED_OBJECT_LIST 0x009ADAE8 +#define RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST 0x009ADAEC +#define RCT2_ADDRESS_TOTAL_NO_IMAGES 0x009ADAF0 + +#define RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK 0x009ADAF8 + #define RCT2_ADDRESS_CURRENT_SOUND_DEVICE 0x009AF280 @@ -164,20 +193,47 @@ #define RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER 0x009DE55E #define RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX 0x009DE560 +#define RCT2_ADDRESS_PALETTE_EFFECT_FRAME_NO 0x009DE584 + +// Flags: +// 0x1 Enable selection +// 0x2 Enable construct selection, see CONSTRUCT_PATH_* +// 0x4 Show yellow arrow, see MAP_ARROW_* +// 0x8 ? #define RCT2_ADDRESS_MAP_SELECTION_FLAGS 0x009DE58A #define RCT2_ADDRESS_MAP_SELECTION_A_X 0x009DE58C #define RCT2_ADDRESS_MAP_SELECTION_B_X 0x009DE58E #define RCT2_ADDRESS_MAP_SELECTION_A_Y 0x009DE590 #define RCT2_ADDRESS_MAP_SELECTION_B_Y 0x009DE592 +// Types: +// 0-3 Corners +// 4 Whole tile +// 5 ? +// 6-9 Quarters +// 10-13 Edges #define RCT2_ADDRESS_MAP_SELECTION_TYPE 0x009DE594 +#define RCT2_ADDRESS_MAP_ARROW_X 0x009DEA48 +#define RCT2_ADDRESS_MAP_ARROW_Y 0x009DEA4A +#define RCT2_ADDRESS_MAP_ARROW_Z 0x009DEA4C +#define RCT2_ADDRESS_MAP_ARROW_DIRECTION 0x009DEA4E + #define RCT2_ADDRESS_SCREEN_FLAGS 0x009DEA68 #define RCT2_ADDRESS_SCREENSHOT_COUNTDOWN 0x009DEA6D +// Note: not only the zeroth bit can be set to control pause +// When paused by saving track 2nd bit is set +// When paused by save menu 1st bit is set +// When paused by pause button 0th bit is set +#define RCT2_ADDRESS_GAME_PAUSED 0x009DEA6E #define RCT2_ADDRESS_PLACE_OBJECT_MODIFIER 0x009DEA70 #define RCT2_ADDRESS_ON_TUTORIAL 0x009DEA71 #define RCT2_ADDRESS_WINDOW_DPI 0x009DEA74 +#define RCT2_ADDRESS_TEXTINPUT_WIDGETINDEX 0x009DEB88 +#define RCT2_ADDRESS_TEXTINPUT_WINDOWNUMBER 0x009DEB8A +#define RCT2_ADDRESS_TEXTINPUT_WINDOWCLASS 0x009DEB8C + #define RCT2_ADDRESS_DSOUND_BUFFERS 0x009E1AB0 #define RCT2_ADDRESS_NUM_DSOUND_DEVICES 0x009E2B88 #define RCT2_ADDRESS_DSOUND_DEVICES 0x009E2B8C @@ -202,15 +258,6 @@ #define RCT2_ADDRESS_G1_ELEMENTS 0x009EBD28 -#define RCT2_ADDRESS_PATH_TYPES 0x009ADA14 - -#define RCT2_ADDRESS_SMALL_SCENERY_ENTRIES 0x009AD1A4 -#define RCT2_ADDRESS_LARGE_SCENERY_ENTRIES 0x009AD594 -#define RCT2_ADDRESS_WALL_SCENERY_ENTRIES 0x009AD794 -#define RCT2_ADDRESS_BANNER_SCENERY_ENTRIES 0x009AD994 -#define RCT2_ADDRESS_PATH_BIT_SCENERY_ENTRIES 0x009ADA54 -#define RCT2_ADDRESS_SCENERY_SET_ENTRIES 0x009ADA90 - //Every pixel changed by rain is stored. //32bit (pixel_offset 24 bit)(pixel_colour 8 bit) //Use the rainPixels[] global in drawing.c from now on @@ -236,15 +283,52 @@ #define RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y 0x00F3EF8C #define RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z 0x00F3EF8E #define RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION 0x00F3EF90 +#define RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE 0x00F3EF91 + +#define RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS 0x00F3EF9E #define RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS 0x00F42B6C +#define RCT2_ADDRESS_ORIGINAL_RCT2_OBJECT_COUNT 0x00F42B70 +#define RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID 0x00F42BBC #define RCT2_ADDRESS_CURR_OBJECT_CHUNK_POINTER 0x00F42BC0 +#define RCT2_ADDRESS_SCENARIO_TEXT_TEMP_OBJECT 0x00F42BC8 + +// 1 if custom objects installed, 0 otherwise +#define RCT2_ADDRESS_CUSTOM_OBJECTS_INSTALLED 0x00F42BDA + #define RCT2_ADDRESS_VOLUME_ADJUST_ZOOM 0x00F438AC #define RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX 0x00F43908 +#define RCT2_ADDRESS_TRACK_PREVIEW_ROTATION 0x00F440AE + +#define RCT2_ADDRESS_TRACK_PREVIEW_X_MIN 0x00F440F9 +#define RCT2_ADDRESS_TRACK_PREVIEW_X_MAX 0x00F440FB +#define RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN 0x00F440FD +#define RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX 0x00F440FF +#define RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN 0x00F44101 +#define RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX 0x00F44103 +#define RCT2_ADDRESS_TRACK_DESIGN_CACHE 0x00F44105 +#define RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE 0x00F44109 +#define RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE 0x00F44119 + +#define RCT2_ADDRESS_TRACK_DESIGN_COST 0x00F4411D + +#define RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE 0x00F44152 + +#define RCT2_ADDRESS_TRACK_LIST 0x00F441EC + +#define RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE 0x00F64ECC +#define RCT2_ADDRESS_SHIFT_PRESS_X_COORDINATE 0x00F64ECE +#define RCT2_ADDRESS_SHIFT_PRESS_Y_COORDINATE 0x00F64ED0 +#define RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR 0x00F64ED2 +#define RCT2_ADDRESS_SCENERY_Z_COORDINATE 0x00F64ED4 + +#define RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED 0x00F64F12 +#define RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED 0x00F64F13 + #define RCT2_ADDRESS_CURRENT_MONTH_YEAR 0x00F663A8 #define RCT2_ADDRESS_CURRENT_MONTH_TICKS 0x00F663AA #define RCT2_ADDRESS_SCENARIO_TICKS 0x00F663AC @@ -257,9 +341,12 @@ #define RCT2_ADDRESS_SPRITES_NEXT_INDEX 0x013573BC #define RCT2_ADDRESS_SPRITES_START_VEHICLE 0x013573BE #define RCT2_ADDRESS_SPRITES_START_PEEP 0x013573C0 -#define RCT2_ADDRESS_SPRITES_START_TEXTFX 0x013573C2 +#define RCT2_ADDRESS_SPRITES_START_MISC 0x013573C2 #define RCT2_ADDRESS_SPRITES_START_LITTER 0x013573C4 +#define RCT2_ADDRESS_PARK_NAME 0x013573D4 +#define RCT2_ADDRESS_PARK_NAME_ARGS 0x013573D8 +#define RCT2_ADDRESS_INITIAL_CASH 0x013573DC #define RCT2_ADDRESS_CURRENT_LOAN 0x013573E0 #define RCT2_ADDRESS_MAXIMUM_LOAN 0x013580F0 #define RCT2_ADDRESS_PARK_FLAGS 0x013573E4 @@ -315,12 +402,15 @@ #define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY 0x013580E7 #define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH 0x013580E8 -#define RCT2_ADDRESS_MAP_MAXIMUM_X_Y 0x01358832 +#define RCT2_ADDRESS_MAP_SIZE_UNITS 0x01358830 +#define RCT2_ADDRESS_MAP_SIZE_MINUS_2 0x01358832 #define RCT2_ADDRESS_MAP_SIZE 0x01358834 +#define RCT2_ADDRESS_MAP_MAX_XY 0x01358836 #define RCT2_ADDRESS_PARK_SIZE 0x013580EA #define RCT2_TOTAL_RIDE_VALUE 0x013580EE +#define RCT2_ADDRESS_PARK_RATING_WARNING_DAYS 0x0135883E #define RCT2_RESEARCH_ITEMS 0x01358844 #define RCT2_ADDRESS_SCENARIO_NAME 0x0135920A @@ -329,6 +419,7 @@ #define RCT2_ADDRESS_PARK_ENTRANCE_X 0x01359350 #define RCT2_ADDRESS_PARK_ENTRANCE_Y 0x01359358 #define RCT2_ADDRESS_PARK_ENTRANCE_Z 0x01359360 +#define RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION 0x01359368 #define RCT2_ADDRESS_CURRENT_TICKS 0x013628F4 #define RCT2_ADDRESS_RIDE_LIST 0x013628F8 @@ -339,6 +430,8 @@ #define RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION 0x0138869E #define RCT2_ADDRESS_RIDE_MEASUREMENTS 0x0138B60C +#define RCT2_ADDRESS_GRASS_SCENERY_TILEPOS 0x013B0E70 + #define RCT2_ADDRESS_CLIMATE 0x013CA746 #define RCT2_ADDRESS_CURRENT_WEATHER 0x013CA74A #define RCT2_ADDRESS_NEXT_WEATHER 0x013CA74B @@ -370,12 +463,10 @@ #define RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER 0x0141ED68 -#define RCT2_ADDRESS_AUDIO_INFO 0x01425B40 +#define RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE 0x0141F56C -#define RCT2_ADDRESS_SOUND_CHANNEL_LIST 0x014262E0 - -#define RCT2_ADDRESS_WATER_RAISE_COST 0x0141F738 -#define RCT2_ADDRESS_WATER_LOWER_COST 0x0141F73C +#define RCT2_ADDRESS_WATER_RAISE_COST 0x0141F738 +#define RCT2_ADDRESS_WATER_LOWER_COST 0x0141F73C #define RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1 0x0141F740 #define RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2 0x0141F741 @@ -466,6 +557,10 @@ #define RCT2_ADDRESS_INPUT_QUEUE 0x01424340 +#define RCT2_ADDRESS_AUDIO_INFO 0x01425B40 + +#define RCT2_ADDRESS_SOUND_CHANNEL_LIST 0x014262E0 + #define RCT2_ADDRESS_COMMON_FORMAT_ARGS 0x013CE952 #define RCT2_ADDRESS_STAFF_MODE_ARRAY 0x013CA672 @@ -485,24 +580,11 @@ #define RCT2_ADDRESS_X_END_POINT_GLOBAL 0x9ABDA8 //sint16 #define RCT2_ADDRESS_X_START_POINT_GLOBAL 0xEDF80C //sint16 #define RCT2_ADDRESS_DPI_LINE_LENGTH_GLOBAL 0x9ABDB0 //uint16 width+pitch +#define RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_OBJECTS 0x009AA00D +#define RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_CONFIG 0x009AB4C6 #pragma endregion -static void RCT2_CALLPROC_EBPSAFE(int address) -{ - #ifdef _MSC_VER - __asm push ebp - __asm call address - __asm pop ebp - #else - __asm__ ( "\ - push ebp \n\ - call %[address] \n\ - pop ebp \n\ - " : [address] "+m" (address) ); - #endif -} - /* Returns the flags register * *Flags register is as follows: @@ -557,45 +639,9 @@ static int RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, #endif } -static void RCT2_CALLPROC_X_EBPSAFE(int address, int _eax, int _ebx, int _ecx, int _edx, int _esi, int _edi, int _ebp) +static int RCT2_CALLPROC_EBPSAFE(int address) { - #ifdef _MSC_VER - __asm { - push ebp - push address - mov eax, _eax - mov ebx, _ebx - mov ecx, _ecx - mov edx, _edx - mov esi, _esi - mov edi, _edi - mov ebp, _ebp - call[esp] - add esp, 4 - pop ebp - } - #else - __asm__ ( "\ - \n\ - push ebx \n\ - push ebp \n\ - push %[address] \n\ - mov eax, %[_eax] \n\ - mov ebx, %[_ebx] \n\ - mov ecx, %[_ecx] \n\ - mov edx, %[_edx] \n\ - mov esi, %[_esi] \n\ - mov edi, %[_edi] \n\ - mov ebp, %[_ebp] \n\ - call [esp] \n\ - add esp, 4 \n\ - pop ebp \n\ - pop ebx \n\ - " : [address] "+m" (address), [_eax] "+m" (_eax), [_ebx] "+m" (_ebx), [_ecx] "+m" (_ecx), [_edx] "+m" (_edx), [_esi] "+m" (_esi), [_edi] "+m" (_edi), [_ebp] "+m" (_ebp) - : - : "eax","ecx","edx","esi","edi" - ); - #endif + return RCT2_CALLPROC_X(address, 0xBBBBBBBB, 0xBBBBBBBB, 0xBBBBBBBB, 0xBBBBBBBB, 0xBBBBBBBB, 0xBBBBBBBB, 0xBBBBBBBB); } /* Returns the flags register diff --git a/src/audio/audio.c b/src/audio/audio.c index 8137a37f8f..2e69cbff2d 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -23,7 +23,7 @@ #include "../config.h" #include "../interface/viewport.h" #include "../interface/window.h" -#include "../platform/osinterface.h" +#include "../platform/platform.h" #include "../world/map.h" #include "../world/sprite.h" #include "audio.h" @@ -43,7 +43,7 @@ void *gTitleMusicChannel = 0; void audio_init(int i) { if (SDL_Init(SDL_INIT_AUDIO) < 0) { - RCT2_ERROR("SDL_Init %s", SDL_GetError()); + log_fatal("SDL_Init %s", SDL_GetError()); exit(-1); } } @@ -693,32 +693,32 @@ int sound_prepare(int sound_id, rct_sound *sound, int channels, int software) rct_sound_effect* sound_effect = sound_get_effect(sound_id); if (sound_effect) { if (sound_effect_loadvars(sound_effect, &bufferdesc.lpwfxFormat, &buffer, &bufferdesc.dwBufferBytes)) { - bufferdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC; - if (channels) { - if (channels == 2) { + if (channels == 0){ + bufferdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC; + } + else if (channels == 2) { bufferdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D | DSBCAPS_STATIC; - } else { + } else { bufferdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | DSBCAPS_STATIC; + } + if (RCT2_GLOBAL(0x009E2B90, uint32)) { + bufferdesc.dwFlags |= DSBCAPS_CTRLPAN; + } + if (software) { + bufferdesc.dwFlags |= DSBCAPS_LOCSOFTWARE; + } + if (SUCCEEDED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->CreateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &bufferdesc, &sound->dsbuffer, 0))) { + if (sound_fill_buffer(sound->dsbuffer, buffer, bufferdesc.dwBufferBytes)) { + sound->id = sound_id; + DSBCAPS caps; + caps.dwSize = sizeof(caps); + sound->dsbuffer->lpVtbl->GetCaps(sound->dsbuffer, &caps); + sound->has_caps = caps.dwFlags; + sound_add(sound); + return 1; } - if (RCT2_GLOBAL(0x009E2B90, uint32)) { - bufferdesc.dwFlags |= DSBCAPS_CTRLPAN; - } - if (software) { - bufferdesc.dwFlags |= DSBCAPS_LOCSOFTWARE; - } - if (SUCCEEDED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->CreateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &bufferdesc, &sound->dsbuffer, 0))) { - if (sound_fill_buffer(sound->dsbuffer, buffer, bufferdesc.dwBufferBytes)) { - sound->id = sound_id; - DSBCAPS caps; - caps.dwSize = sizeof(caps); - sound->dsbuffer->lpVtbl->GetCaps(sound->dsbuffer, &caps); - sound->has_caps = caps.dwFlags; - sound_add(sound); - return 1; - } - sound->dsbuffer->lpVtbl->Release(sound->dsbuffer); - sound->dsbuffer = 0; - } + sound->dsbuffer->lpVtbl->Release(sound->dsbuffer); + sound->dsbuffer = 0; } sound->dsbuffer = 0; } @@ -1329,7 +1329,7 @@ int dsound_create_primary_buffer(int a, int device, int channels, int samples, i if (FAILED(DirectSoundCreate(&dsdevice->guid, &RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), 0))) { return 0; } - if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->SetCooperativeLevel(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), RCT2_GLOBAL(0x009E2D70, HWND), DSSCL_NORMAL)) || + if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->SetCooperativeLevel(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), windows_get_window_handle(), DSSCL_NORMAL)) || FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->CreateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &bufferdesc, &RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER), 0))) { RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->Release(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)); RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND) = 0; @@ -1374,7 +1374,7 @@ int dsound_create_primary_buffer(int a, int device, int channels, int samples, i if (FAILED(DirectSoundCreate(&dsdevice->guid, &RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), 0))) { return 0; } - if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->SetCooperativeLevel(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), RCT2_GLOBAL(0x009E2D70, HWND), DSSCL_PRIORITY))) { + if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->SetCooperativeLevel(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), windows_get_window_handle(), DSSCL_PRIORITY))) { RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->Release(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)); RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND) = 0; return 0; @@ -1427,13 +1427,8 @@ int sound_play_panned(int sound_id, int ebx, sint16 x, sint16 y, sint16 z) RCT2_GLOBAL(0x00F438AD, uint8) = 0; int volume = 0; if (ebx == 0x8001) { - sint16 x2 = x & 0xFFE0; // round by 32 - sint16 y2 = y & 0xFFE0; - if (x2 < 0x1FFF && y2 < 0x1FFF) { - rct_map_element* mapelement = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[((y2 * 256 + x2) & 0xFFFF) / 8]; - while (mapelement->type & MAP_ELEMENT_TYPE_MASK) { - mapelement++; - } + rct_map_element* mapelement = map_get_surface_element_at(x / 32, y / 32); + if (mapelement) { if ((mapelement->base_height * 8) - 5 > z) { RCT2_GLOBAL(0x00F438AD, uint8) = 10; } @@ -1481,13 +1476,13 @@ int sound_play_panned(int sound_id, int ebx, sint16 x, sint16 y, sint16 z) while (other_sound->id != 0xFFFF) { i++; other_sound = &RCT2_ADDRESS(0x009AF484, rct_other_sound)[i]; - if (i > RCT2_GLOBAL(0x009AAC76, uint8)) { // too many sounds playing + if (i > RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MAX_NO_SOUNDS, uint8)) { // too many sounds playing return sound_id; } } other_sound->id = sound_id; int pan; - if (ebx == 0x8000) { + if (ebx == (sint16)0x8000) { pan = 0; } else { int x2 = ebx << 16; @@ -1544,13 +1539,32 @@ void stop_completed_sounds() */ void start_title_music() { - if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)) && RCT2_GLOBAL(0x009AF59D, uint8) & 1 && RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1) { + int musicPathId; + switch (gConfigSound.title_music) { + default: + return; + case 1: + musicPathId = PATH_ID_CSS50; + break; + case 2: + musicPathId = PATH_ID_CSS17; + break; + case 3: + if (rand() & 1) + musicPathId = PATH_ID_CSS50; + else + musicPathId = PATH_ID_CSS17; + break; + } + + if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)) && RCT2_GLOBAL(0x009AF59D, uint8) & 1 + && RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) { if (!RCT2_GLOBAL(0x009AF600, uint8)) { #ifdef USE_MIXER - gTitleMusicChannel = Mixer_Play_Music(PATH_ID_CSS17); + gTitleMusicChannel = Mixer_Play_Music(musicPathId, MIXER_LOOP_INFINITE, true); #else RCT2_GLOBAL(0x014241BC, uint32) = 1; - int result = sound_channel_load_file2(3, (char*)get_file_path(PATH_ID_CSS17), 0); + int result = sound_channel_load_file2(3, (char*)get_file_path(musicPathId), 0); RCT2_GLOBAL(0x014241BC, uint32) = 0; if (result) { RCT2_GLOBAL(0x014241BC, uint32) = 1; @@ -1688,18 +1702,15 @@ void audio_init1() audio_init2(devicenum); int m = 0; do { - rct_ride_music_info* ride_music_info = &RCT2_GLOBAL(0x009AF1C8, rct_ride_music_info*)[m]; + rct_ride_music_info* ride_music_info = ride_music_info_list[m]; const char* path = get_file_path(ride_music_info->pathid); - RCT2_GLOBAL(0x014241BC, uint32) = 3; - HANDLE hfile = osinterface_file_open(path); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (hfile != INVALID_HANDLE_VALUE) { - RCT2_GLOBAL(0x014241BC, uint32) = 3; - osinterface_file_read(hfile, &RCT2_GLOBAL(0x009AF47E, uint32), 4); - osinterface_file_close(hfile); + FILE *file = fopen(path, "rb"); + if (file != NULL) { + fread(&RCT2_GLOBAL(0x009AF47E, uint32), 4, 1, file); + fclose(file); RCT2_GLOBAL(0x014241BC, uint32) = 0; if (RCT2_GLOBAL(0x009AF47E, uint32) == 0x78787878) { - ride_music_info->var_0 = 0; + ride_music_info->length = 0; } } m++; @@ -1742,7 +1753,7 @@ void audio_init2(int device) rct_dsdevice dsdevice = RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[device]; RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID) = dsdevice.guid; RCT2_GLOBAL(0x009AAC5C, uint8) = 1; - config_save(); + config_save_default(); RCT2_GLOBAL(0x014241BC, uint32) = 1; int successtimer = audio_create_timer(); RCT2_GLOBAL(0x014241BC, uint32) = 0; @@ -1753,10 +1764,22 @@ void audio_init2(int device) ride_music->rideid = -1; } } + + // Used by original code for directsound if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & 1 << 4)) { - gSound_config.forced_software_buffering = RCT2_GLOBAL(0x001425B74, uint32) != RCT2_GLOBAL(0x001425B78, uint32) || RCT2_GLOBAL(0x001425B74, uint32) != RCT2_GLOBAL(0x001425B7C, uint32); RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= 1 << 4; - config_save(); + } + + // When all sound code is reversed this can be removed. + if (!gConfigSound.sound){ + toggle_all_sounds(); + } + + // When all sound code is reversed this can be removed. + if (!gConfigSound.ride_music){ + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) ^= 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) == 0) + stop_ride_music(); } } @@ -1784,19 +1807,34 @@ void audio_close() } } +/* rct2: 0x006BAB8A */ +void toggle_all_sounds(){ + // When all sound code is reversed replace with gConfigSound.sound + RCT2_GLOBAL(0x009AF59D, uint8) ^= 1; + if (RCT2_GLOBAL(0x009AF59D, uint8) == 0) { + stop_title_music(); + pause_sounds(); + } + else{ + unpause_sounds(); + } +} + /** * * rct2: 0x006BABB4 */ void pause_sounds() { - if (++RCT2_GLOBAL(0x009AF59C, uint8) == 1) { + // When all sound code is reversed replace with gConfigSound.sound + RCT2_GLOBAL(0x009AF59C, uint8) = 1; + if (RCT2_GLOBAL(0x009AF59C, uint8) == 1) { stop_other_sounds(); stop_vehicle_sounds(); stop_ride_music(); stop_crowd_sound(); } - g_sounds_disabled = 1; + gConfigSound.sound = 0; } /** @@ -1805,8 +1843,9 @@ void pause_sounds() */ void unpause_sounds() { - RCT2_GLOBAL(0x009AF59C, uint8)--; - g_sounds_disabled = 0; + // When all sound code is reversed replace with gConfigSound.sound + RCT2_GLOBAL(0x009AF59C, uint8) = 0; + gConfigSound.sound = 1; } /** @@ -1842,4 +1881,4 @@ void stop_vehicle_sounds() vehicle_sound->id = 0xFFFF; } } -} \ No newline at end of file +} diff --git a/src/audio/audio.h b/src/audio/audio.h index 3c2621afa9..037206227a 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -141,12 +141,13 @@ typedef struct { } rct_ride_music; typedef struct { - uint32 var_0; - uint32 var_4; + uint32 length; + uint32 offset; uint8 pathid; //0x8 uint8 var_9; } rct_ride_music_info; +extern rct_ride_music_info* ride_music_info_list[]; extern rct_vehicle_sound gVehicleSoundList[AUDIO_MAX_VEHICLE_SOUNDS]; extern rct_vehicle_sound_params gVehicleSoundParamsList[AUDIO_MAX_VEHICLE_SOUNDS]; extern rct_vehicle_sound_params *gVehicleSoundParamsListEnd; @@ -218,13 +219,10 @@ void audio_init1(); void audio_init2(int device); void audio_close(); void pause_sounds(); +void toggle_all_sounds(); void unpause_sounds(); void stop_vehicle_sounds(); -// 0x009AF59C probably does the same job -// once it's confirmed and calls in pause_sounds() are reversed, it can be used instead of this -int g_sounds_disabled; - typedef enum { SOUND_LIFT_1 = 0, SOUND_TRACK_FRICTION_1 = 1, diff --git a/src/audio/mixer.cpp b/src/audio/mixer.cpp index 042f349a78..6f242f933b 100644 --- a/src/audio/mixer.cpp +++ b/src/audio/mixer.cpp @@ -25,52 +25,113 @@ extern "C" { #include "../config.h" #include "../platform/platform.h" #include "audio.h" + #include "../localisation/localisation.h" } #include "mixer.h" Mixer gMixer; -Sample::Sample() +Source::~Source() +{ + +} + +unsigned long Source::GetSome(unsigned long offset, const uint8** data, unsigned long length) +{ + if (offset >= Length()) { + return 0; + } + unsigned long size = length; + if (offset + length > Length()) { + size = Length() - offset; + } + return Read(offset, data, size); +} + +unsigned long Source::Length() +{ + return length; +} + +const AudioFormat& Source::Format() +{ + return format; +} + +Source_Null::Source_Null() +{ + length = 0; +} + +unsigned long Source_Null::Read(unsigned long offset, const uint8** data, unsigned long length) +{ + return 0; +} + +Source_Sample::Source_Sample() { data = 0; length = 0; issdlwav = false; } -Sample::~Sample() +Source_Sample::~Source_Sample() { Unload(); } -bool Sample::Load(const char* filename) +unsigned long Source_Sample::Read(unsigned long offset, const uint8** data, unsigned long length) { + *data = &Source_Sample::data[offset]; + return length; +} + +bool Source_Sample::LoadWAV(const char* filename) +{ + log_verbose("Source_Sample::LoadWAV(%s)", filename); + + utf8 utf8filename[512]; + win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); + Unload(); - SDL_RWops* rw = SDL_RWFromFile(filename, "rb"); - if (!rw) { - SDL_RWclose(rw); + SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb"); + if (rw == NULL) { + log_verbose("Error loading %s", filename); return false; } + SDL_AudioSpec audiospec; memset(&audiospec, 0, sizeof(audiospec)); SDL_AudioSpec* spec = SDL_LoadWAV_RW(rw, false, &audiospec, &data, (Uint32*)&length); + SDL_RWclose(rw); + if (spec != NULL) { format.freq = spec->freq; format.format = spec->format; format.channels = spec->channels; issdlwav = true; } else { + log_verbose("Error loading %s, unsupported WAV format", filename); return false; } + return true; } -bool Sample::LoadCSS1(const char* filename, unsigned int offset) +bool Source_Sample::LoadCSS1(const char* filename, unsigned int offset) { + log_verbose("Source_Sample::LoadCSS1(%s, %d)", filename, offset); + + utf8 utf8filename[512]; + win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); + Unload(); - SDL_RWops* rw = SDL_RWFromFile(filename, "rb"); - if (!rw) { + SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb"); + if (rw == NULL) { + log_verbose("Unable to load %s", filename); return false; } + Uint32 numsounds; SDL_RWread(rw, &numsounds, sizeof(numsounds), 1); if (offset > numsounds) { @@ -89,13 +150,18 @@ bool Sample::LoadCSS1(const char* filename, unsigned int offset) format.freq = waveformat.nSamplesPerSec; format.format = AUDIO_S16LSB; format.channels = waveformat.nChannels; - data = new uint8[length]; + data = new (std::nothrow) uint8[length]; + if (!data) { + log_verbose("Unable to allocate data"); + SDL_RWclose(rw); + return false; + } SDL_RWread(rw, data, length, 1); SDL_RWclose(rw); return true; } -void Sample::Unload() +void Source_Sample::Unload() { if (data) { if (issdlwav) { @@ -109,16 +175,11 @@ void Sample::Unload() length = 0; } -bool Sample::Loaded() +bool Source_Sample::Convert(AudioFormat format) { - return data != 0; -} - -bool Sample::Convert(AudioFormat format) -{ - if(Sample::format.format != format.format || Sample::format.channels != format.channels || Sample::format.freq != format.freq){ + if(Source_Sample::format.format != format.format || Source_Sample::format.channels != format.channels || Source_Sample::format.freq != format.freq){ SDL_AudioCVT cvt; - if (SDL_BuildAudioCVT(&cvt, Sample::format.format, Sample::format.channels, Sample::format.freq, format.format, format.channels, format.freq) < 0) { + if (SDL_BuildAudioCVT(&cvt, Source_Sample::format.format, Source_Sample::format.channels, Source_Sample::format.freq, format.format, format.channels, format.freq) < 0) { return false; } cvt.len = length; @@ -131,69 +192,149 @@ bool Sample::Convert(AudioFormat format) Unload(); data = cvt.buf; length = cvt.len_cvt; - Sample::format = format; + Source_Sample::format = format; return true; } return false; } -const uint8* Sample::Data() +Source_SampleStream::Source_SampleStream() { - return data; + length = 0; + rw = NULL; + buffer = 0; + buffersize = 0; } -unsigned long Sample::Length() +Source_SampleStream::~Source_SampleStream() { - return length; + Unload(); } -Stream::Stream() +unsigned long Source_SampleStream::Read(unsigned long offset, const uint8** data, unsigned long length) { - sourcetype = SOURCE_NONE; + if (length > buffersize) { + if (buffer) { + delete[] buffer; + } + buffer = new (std::nothrow) uint8[length]; + if (!buffer) { + return 0; + } + buffersize = length; + } + Sint64 currentposition = SDL_RWtell(rw); + if (currentposition == -1) { + return 0; + } + if (currentposition - databegin != offset) { + Sint64 newposition = SDL_RWseek(rw, databegin + offset, SEEK_SET); + if (newposition == -1) { + return 0; + } + currentposition = newposition; + } + *data = buffer; + int read = SDL_RWread(rw, buffer, 1, length); + if (read == -1) { + return 0; + } + return read; } -unsigned long Stream::GetSome(unsigned long offset, const uint8** data, unsigned long length) +bool Source_SampleStream::LoadWAV(SDL_RWops* rw) { - unsigned long size = length; - switch(sourcetype) { - case SOURCE_SAMPLE: - if (offset >= sample->Length()) { - return 0; - } - if (offset + length > sample->Length()) { - size = sample->Length() - offset; - } - *data = &sample->Data()[offset]; - return size; - break; + Unload(); + if (rw == NULL) { + return false; + } + Source_SampleStream::rw = rw; + Uint32 chunk_id = SDL_ReadLE32(rw); + const Uint32 RIFF = 0x46464952; + if (chunk_id != RIFF) { + log_verbose("Not a WAV file"); + return false; + } + Uint32 chunk_size = SDL_ReadLE32(rw); + Uint32 chunk_format = SDL_ReadLE32(rw); + const Uint32 WAVE = 0x45564157; + if (chunk_format != WAVE) { + log_verbose("Not in WAVE format"); + return false; + } + const Uint32 FMT = 0x20746D66; + Uint32 fmtchunk_size = FindChunk(rw, FMT); + if (!fmtchunk_size) { + log_verbose("Could not find FMT chunk"); + return false; + } + Uint64 chunkstart = SDL_RWtell(rw); + PCMWAVEFORMAT waveformat; + SDL_RWread(rw, &waveformat, sizeof(waveformat), 1); + SDL_RWseek(rw, chunkstart + fmtchunk_size, RW_SEEK_SET); + if (waveformat.wf.wFormatTag != WAVE_FORMAT_PCM) { + log_verbose("Not in proper format"); + return false; + } + format.freq = waveformat.wf.nSamplesPerSec; + switch (waveformat.wBitsPerSample) { + case 8: + format.format = AUDIO_U8; + break; + case 16: + format.format = AUDIO_S16LSB; + break; + default: + log_verbose("Invalid bits per sample"); + return false; + break; + } + format.channels = waveformat.wf.nChannels; + const Uint32 DATA = 0x61746164; + Uint32 datachunk_size = FindChunk(rw, DATA); + if (!datachunk_size) { + log_verbose("Could not find DATA chunk"); + return false; + } + length = datachunk_size; + databegin = SDL_RWtell(rw); + return true; +} + +Uint32 Source_SampleStream::FindChunk(SDL_RWops* rw, Uint32 wanted_id) +{ + Uint32 subchunk_id = SDL_ReadLE32(rw); + Uint32 subchunk_size = SDL_ReadLE32(rw); + if (subchunk_id == wanted_id) { + return subchunk_size; + } + const Uint32 FACT = 0x74636166; + const Uint32 LIST = 0x5453494c; + const Uint32 BEXT = 0x74786562; + const Uint32 JUNK = 0x4B4E554A; + while (subchunk_id == FACT || subchunk_id == LIST || subchunk_id == BEXT || subchunk_id == JUNK) { + SDL_RWseek(rw, subchunk_size, RW_SEEK_CUR); + subchunk_id = SDL_ReadLE32(rw); + subchunk_size = SDL_ReadLE32(rw); + if (subchunk_id == wanted_id) { + return subchunk_size; + } } return 0; } -unsigned long Stream::Length() +void Source_SampleStream::Unload() { - switch(sourcetype) { - case SOURCE_SAMPLE: - return sample->Length(); - break; + if (rw) { + SDL_RWclose(rw); + rw = NULL; } - return 0; -} - -void Stream::SetSource_Sample(Sample& sample) -{ - sourcetype = SOURCE_SAMPLE; - Stream::sample = &sample; -} - -const AudioFormat* Stream::Format() -{ - switch(sourcetype) { - case SOURCE_SAMPLE: - return &sample->format; - break; + length = 0; + if (buffer) { + delete[] buffer; + buffer = 0; } - return 0; + buffersize = 0; } Channel::Channel() @@ -202,10 +343,14 @@ Channel::Channel() SetRate(1); SetVolume(SDL_MIX_MAXVOLUME); oldvolume = 0; + oldvolume_l = 0; + oldvolume_r = 0; SetPan(0.5f); done = true; stopping = false; - stream = 0; + source = 0; + deletesourceondone = false; + group = MIXER_GROUP_NONE; } Channel::~Channel() @@ -214,11 +359,14 @@ Channel::~Channel() speex_resampler_destroy(resampler); resampler = 0; } + if (deletesourceondone) { + delete source; + } } -void Channel::Play(Stream& stream, int loop = MIXER_LOOP_NONE) +void Channel::Play(Source& source, int loop = MIXER_LOOP_NONE) { - Channel::stream = &stream; + Channel::source = &source; Channel::loop = loop; offset = 0; done = false; @@ -252,8 +400,15 @@ void Channel::SetPan(float pan) if (pan < 0) { Channel::pan = 0; } - volume_l = (float)sin((1.0 - Channel::pan) * M_PI / 2.0); - volume_r = (float)sin(Channel::pan * M_PI / 2.0); + double decibels = (abs(Channel::pan - 0.5) * 2.0) * 100.0; + double attenuation = pow(10, decibels / 20.0); + if (Channel::pan <= 0.5) { + volume_l = 1.0; + volume_r = float(1.0 / attenuation); + } else { + volume_r = 1.0; + volume_l = float(1.0 / attenuation); + } } bool Channel::IsPlaying() @@ -268,14 +423,30 @@ unsigned long Channel::GetOffset() bool Channel::SetOffset(unsigned long offset) { - if (stream && offset < stream->Length()) { - int samplesize = stream->Format()->channels * stream->Format()->BytesPerSample(); + if (source && offset < source->Length()) { + int samplesize = source->Format().channels * source->Format().BytesPerSample(); Channel::offset = (offset / samplesize) * samplesize; return true; } return false; } +void Channel::SetGroup(int group) +{ + Channel::group = group; +} + +Mixer::Mixer() +{ + effectbuffer = 0; + for (int i = 0; i < countof(css1sources); i++) { + css1sources[i] = 0; + } + for (int i = 0; i < countof(musicsources); i++) { + musicsources[i] = 0; + } +} + void Mixer::Init(const char* device) { Close(); @@ -292,10 +463,15 @@ void Mixer::Init(const char* device) format.channels = have.channels; format.freq = have.freq; const char* filename = get_file_path(PATH_ID_CSS1); - for (int i = 0; i < SOUND_MAXID; i++) { - css1samples[i].LoadCSS1(filename, i); - css1samples[i].Convert(format); // convert to audio output format, saves some cpu usage but requires a bit more memory, optional - css1streams[i].SetSource_Sample(css1samples[i]); + for (int i = 0; i < countof(css1sources); i++) { + Source_Sample* source_sample = new Source_Sample; + if (source_sample->LoadCSS1(filename, i)) { + source_sample->Convert(format); // convert to audio output format, saves some cpu usage but requires a bit more memory, optional + css1sources[i] = source_sample; + } else { + css1sources[i] = &source_null; + delete source_sample; + } } effectbuffer = new uint8[(have.samples * format.BytesPerSample() * format.channels)]; SDL_PauseAudioDevice(deviceid, 0); @@ -310,7 +486,22 @@ void Mixer::Close() } Unlock(); SDL_CloseAudioDevice(deviceid); - delete[] effectbuffer; + for (int i = 0; i < countof(css1sources); i++) { + if (css1sources[i] && css1sources[i] != &source_null) { + delete css1sources[i]; + css1sources[i] = 0; + } + } + for (int i = 0; i < countof(musicsources); i++) { + if (musicsources[i] && musicsources[i] != &source_null) { + delete musicsources[i]; + musicsources[i] = 0; + } + } + if (effectbuffer) { + delete[] effectbuffer; + effectbuffer = 0; + } } void Mixer::Lock() @@ -323,14 +514,14 @@ void Mixer::Unlock() SDL_UnlockAudioDevice(deviceid); } -Channel* Mixer::Play(Stream& stream, int loop, bool deleteondone) +Channel* Mixer::Play(Source& source, int loop, bool deleteondone, bool deletesourceondone) { Lock(); - Channel* newchannel = new (std::nothrow) Channel(); + Channel* newchannel = new (std::nothrow) Channel; if (newchannel) { - newchannel->Play(stream, loop); + newchannel->Play(source, loop); newchannel->deleteondone = deleteondone; - newchannel->stopping = false; + newchannel->deletesourceondone = deletesourceondone; channels.push_back(newchannel); } Unlock(); @@ -346,13 +537,20 @@ void Mixer::Stop(Channel& channel) bool Mixer::LoadMusic(int pathid) { - if (pathid >= PATH_ID_END) { + if (pathid >= countof(musicsources)) { return false; } - if (!musicsamples[pathid].Loaded()) { + if (!musicsources[pathid]) { const char* filename = get_file_path(pathid); - musicstreams[pathid].SetSource_Sample(musicsamples[pathid]); - return musicsamples[pathid].Load(filename); + Source_Sample* source_sample = new Source_Sample; + if (source_sample->LoadWAV(filename)) { + musicsources[pathid] = source_sample; + return true; + } else { + delete source_sample; + musicsources[pathid] = &source_null; + return false; + } } else { return true; } @@ -376,8 +574,8 @@ void SDLCALL Mixer::Callback(void* arg, uint8* stream, int length) void Mixer::MixChannel(Channel& channel, uint8* data, int length) { - if (channel.stream && !channel.done) { - AudioFormat streamformat = *channel.stream->Format(); + if (channel.source && channel.source->Length() > 0 && !channel.done) { + AudioFormat streamformat = channel.source->Format(); int loaded = 0; SDL_AudioCVT cvt; cvt.len_ratio = 1; @@ -391,9 +589,9 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) } int samplestoread = (int)((samples - samplesloaded) * rate); int lengthloaded = 0; - if (channel.offset < channel.stream->Length()) { + if (channel.offset < channel.source->Length()) { bool mustconvert = false; - if (MustConvert(*channel.stream)) { + if (MustConvert(*channel.source)) { if (SDL_BuildAudioCVT(&cvt, streamformat.format, streamformat.channels, streamformat.freq, Mixer::format.format, Mixer::format.channels, Mixer::format.freq) == -1) { break; } @@ -402,12 +600,11 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) const uint8* datastream = 0; int toread = (int)(samplestoread / cvt.len_ratio) * samplesize; - int readfromstream = (channel.stream->GetSome(channel.offset, &datastream, toread)); + int readfromstream = (channel.source->GetSome(channel.offset, &datastream, toread)); if (readfromstream == 0) { break; } - int volume = channel.volume; uint8* dataconverted = 0; const uint8* tomix = 0; @@ -465,12 +662,16 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) mixlength = length - loaded; } - int startvolume = channel.oldvolume; - int endvolume = channel.volume; + float volumeadjust = (gConfigSound.master_volume / 100.0f); + if (channel.group == MIXER_GROUP_MUSIC) { + volumeadjust *= (gConfigSound.music_volume / 100.0f); + } + int startvolume = (int)(channel.oldvolume * volumeadjust); + int endvolume = (int)(channel.volume * volumeadjust); if (channel.stopping) { endvolume = 0; } - int mixvolume = volume; + int mixvolume = (int)(channel.volume * volumeadjust); if (startvolume != endvolume) { // fade between volume levels to smooth out sound and minimize clicks from sudden volume changes if (!effectbufferloaded) { @@ -501,7 +702,7 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) loaded += lengthloaded; - if (channel.loop != 0 && channel.offset >= channel.stream->Length()) { + if (channel.loop != 0 && channel.offset >= channel.source->Length()) { if (channel.loop != -1) { channel.loop--; } @@ -510,7 +711,9 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) } while(loaded < length && channel.loop != 0 && !channel.stopping); channel.oldvolume = channel.volume; - if (channel.loop == 0 && channel.offset >= channel.stream->Length()) { + channel.oldvolume_l = channel.volume_l; + channel.oldvolume_r = channel.volume_r; + if (channel.loop == 0 && channel.offset >= channel.source->Length()) { channel.done = true; } } @@ -518,21 +721,19 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) void Mixer::EffectPanS16(Channel& channel, sint16* data, int length) { - float left = channel.volume_l; - float right = channel.volume_r; for (int i = 0; i < length * 2; i += 2) { - data[i] = (sint16)(data[i] * left); - data[i + 1] = (sint16)(data[i + 1] * right); + float t = (float)i / (length * 2); + data[i] = (sint16)(data[i] * ((1.0 - t) * channel.oldvolume_l + t * channel.volume_l)); + data[i + 1] = (sint16)(data[i + 1] * ((1.0 - t) * channel.oldvolume_r + t * channel.volume_r)); } } void Mixer::EffectPanU8(Channel& channel, uint8* data, int length) { - float left = channel.volume_l; - float right = channel.volume_r; for (int i = 0; i < length * 2; i += 2) { - data[i] = (uint8)(data[i] * left); - data[i + 1] = (uint8)(data[i + 1] * right); + float t = (float)i / (length * 2); + data[i] = (uint8)(data[i] * ((1.0 - t) * channel.oldvolume_l + t * channel.volume_l)); + data[i + 1] = (uint8)(data[i + 1] * ((1.0 - t) * channel.oldvolume_r + t * channel.volume_r)); } } @@ -556,13 +757,10 @@ void Mixer::EffectFadeU8(uint8* data, int length, int startvolume, int endvolume } } -bool Mixer::MustConvert(Stream& stream) +bool Mixer::MustConvert(Source& source) { - const AudioFormat* streamformat = stream.Format(); - if (!streamformat) { - return false; - } - if (streamformat->format != format.format || streamformat->channels != format.channels || streamformat->freq != format.freq) { + const AudioFormat sourceformat = source.Format(); + if (sourceformat.format != format.format || sourceformat.channels != format.channels || sourceformat.freq != format.freq) { return true; } return false; @@ -591,11 +789,11 @@ void Mixer_Init(const char* device) void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, int deleteondone) { - if (id >= SOUND_MAXID) { + if (id >= countof(gMixer.css1sources)) { return 0; } gMixer.Lock(); - Channel* channel = gMixer.Play(gMixer.css1streams[id], loop, deleteondone != 0); + Channel* channel = gMixer.Play(*gMixer.css1sources[id], loop, deleteondone != 0, false); if (channel) { channel->SetVolume(volume); channel->SetPan(pan); @@ -646,10 +844,44 @@ int Mixer_Channel_SetOffset(void* channel, unsigned long offset) return ((Channel*)channel)->SetOffset(offset); } -void* Mixer_Play_Music(int pathid) +void Mixer_Channel_SetGroup(void* channel, int group) { - if (gMixer.LoadMusic(pathid)) { - return gMixer.Play(gMixer.musicstreams[pathid], MIXER_LOOP_INFINITE, false); + ((Channel*)channel)->SetGroup(group); +} + +void* Mixer_Play_Music(int pathid, int loop, int streaming) +{ + if (streaming) { + const char* filename = get_file_path(pathid); + + utf8 utf8filename[512]; + win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); + + SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb"); + if (rw == NULL) { + return 0; + } + Source_SampleStream* source_samplestream = new Source_SampleStream; + if (source_samplestream->LoadWAV(rw)) { + Channel* channel = gMixer.Play(*source_samplestream, loop, false, true); + if (!channel) { + delete source_samplestream; + } else { + channel->SetGroup(MIXER_GROUP_MUSIC); + } + return channel; + } else { + delete source_samplestream; + return 0; + } + } else { + if (gMixer.LoadMusic(pathid)) { + Channel* channel = gMixer.Play(*gMixer.musicsources[pathid], MIXER_LOOP_INFINITE, false, false); + if (channel) { + channel->SetGroup(MIXER_GROUP_MUSIC); + } + return channel; + } } return 0; } \ No newline at end of file diff --git a/src/audio/mixer.h b/src/audio/mixer.h index 6920986e92..679f7ef0af 100644 --- a/src/audio/mixer.h +++ b/src/audio/mixer.h @@ -29,6 +29,11 @@ #define MIXER_LOOP_NONE 0 #define MIXER_LOOP_INFINITE -1 +enum { + MIXER_GROUP_NONE, + MIXER_GROUP_MUSIC, +}; + #ifdef __cplusplus #include @@ -43,45 +48,73 @@ struct AudioFormat { int channels; }; -class Sample +class Source { public: - Sample(); - ~Sample(); - bool Load(const char* filename); - bool LoadCSS1(const char* filename, unsigned int offset); - void Unload(); - bool Loaded(); - bool Convert(AudioFormat format); - const uint8* Data(); - unsigned long Length(); - - friend class Stream; - -private: - AudioFormat format; - uint8* data; - unsigned long length; - bool issdlwav; -}; - -class Stream -{ -public: - Stream(); + virtual ~Source(); unsigned long GetSome(unsigned long offset, const uint8** data, unsigned long length); unsigned long Length(); - void SetSource_Sample(Sample& sample); - const AudioFormat* Format(); + const AudioFormat& Format(); friend class Mixer; +protected: + virtual unsigned long Read(unsigned long offset, const uint8** data, unsigned long length) = 0; + + AudioFormat format; + unsigned long length; +}; + +class Source_Null : public Source +{ +public: + Source_Null(); + +protected: + unsigned long Read(unsigned long offset, const uint8** data, unsigned long length); +}; + +class Source_Sample : public Source +{ +public: + Source_Sample(); + ~Source_Sample(); + bool LoadWAV(const char* filename); + bool LoadCSS1(const char* filename, unsigned int offset); + + friend class Mixer; + +protected: + bool Convert(AudioFormat format); + private: - enum { - SOURCE_NONE = 0, - SOURCE_SAMPLE - } sourcetype; - Sample* sample; + void Unload(); + + uint8* data; + bool issdlwav; + +protected: + unsigned long Read(unsigned long offset, const uint8** data, unsigned long length); +}; + +class Source_SampleStream : public Source +{ +public: + Source_SampleStream(); + ~Source_SampleStream(); + bool LoadWAV(SDL_RWops* rw); + +private: + Uint32 FindChunk(SDL_RWops* rw, Uint32 wanted_id); + void Unload(); + + SDL_RWops* rw; + Uint64 databegin; + uint8* buffer; + unsigned long buffersize; + +protected: + unsigned long Read(unsigned long offset, const uint8** data, unsigned long length); }; class Channel @@ -89,13 +122,14 @@ class Channel public: Channel(); ~Channel(); - void Play(Stream& stream, int loop); + void Play(Source& source, int loop); void SetRate(double rate); void SetVolume(int volume); void SetPan(float pan); bool IsPlaying(); unsigned long GetOffset(); bool SetOffset(unsigned long offset); + void SetGroup(int group); friend class Mixer; @@ -105,28 +139,32 @@ private: double rate; int volume; float volume_l, volume_r; + float oldvolume_l, oldvolume_r; float pan; bool done; bool deleteondone; + bool deletesourceondone; bool stopping; int oldvolume; + int group; SpeexResamplerState* resampler; - Stream* stream; + Source* source; }; class Mixer { public: + Mixer(); void Init(const char* device); void Close(); void Lock(); void Unlock(); - Channel* Play(Stream& stream, int loop, bool deleteondone); + Channel* Play(Source& source, int loop, bool deleteondone, bool deletesourceondone); void Stop(Channel& channel); bool LoadMusic(int pathid); - Stream css1streams[SOUND_MAXID]; - Stream musicstreams[PATH_ID_END]; + Source* css1sources[SOUND_MAXID]; + Source* musicsources[PATH_ID_END]; private: static void SDLCALL Callback(void* arg, uint8* data, int length); @@ -135,14 +173,13 @@ private: void EffectPanU8(Channel& channel, uint8* data, int length); void EffectFadeS16(sint16* data, int length, int startvolume, int endvolume); void EffectFadeU8(uint8* data, int length, int startvolume, int endvolume); - bool MustConvert(Stream& stream); + bool MustConvert(Source& source); bool Convert(SDL_AudioCVT& cvt, const uint8* data, unsigned long length, uint8** dataout); SDL_AudioDeviceID deviceid; AudioFormat format; uint8* effectbuffer; - Sample css1samples[SOUND_MAXID]; - Sample musicsamples[PATH_ID_END]; std::list channels; + Source_Null source_null; }; extern "C" @@ -158,7 +195,8 @@ void Mixer_Channel_Rate(void* channel, double rate); int Mixer_Channel_IsPlaying(void* channel); unsigned long Mixer_Channel_GetOffset(void* channel); int Mixer_Channel_SetOffset(void* channel, unsigned long offset); -void* Mixer_Play_Music(int pathid); +void Mixer_Channel_SetGroup(void* channel, int group); +void* Mixer_Play_Music(int pathid, int loop, int streaming); static int DStoMixerVolume(int volume) { return (int)(SDL_MIX_MAXVOLUME * (SDL_pow(10, (float)volume / 2000))); }; static float DStoMixerPan(int pan) { return (((float)pan + -DSBPAN_LEFT) / DSBPAN_RIGHT) / 2; }; diff --git a/src/cheats.h b/src/cheats.h new file mode 100644 index 0000000000..2ef58d5260 --- /dev/null +++ b/src/cheats.h @@ -0,0 +1,25 @@ +/***************************************************************************** + * Copyright (c) 2015 Michael Steenbeek + * 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 _CHEATS_H_ +#define _CHEATS_H_ + +int gSandboxMode; +#endif diff --git a/src/cmdline.c b/src/cmdline.c index 3964c2f2be..c964e26e20 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -18,22 +18,35 @@ * along with this program. If not, see . *****************************************************************************/ -#ifdef _MSC_VER #include -#endif #include #include "addresses.h" #include "cmdline.h" +#include "interface/screenshot.h" #include "openrct2.h" #include "platform/platform.h" +#include "util/util.h" + +#ifdef ENABLE_TESTS + #include "../test/tests.h" +#else + static int cmdline_for_test_error(const char **argv, int argc) + { + printf("OpenRCT2 has not been built with the test suite.\n"); + return -1; + } +#endif typedef struct tm tm_t; typedef struct argparse_option argparse_option_t; typedef struct argparse argparse_t; +typedef int (*cmdline_action)(const char **argv, int argc); + int gExitCode = 0; static void print_launch_information(); +static int cmdline_call_action(const char **argv, int argc); static const char *const usage[] = { "openrct2 [options] []", @@ -50,10 +63,6 @@ static const char *const usage[] = { */ int cmdline_run(const char **argv, int argc) { - // For argparse's sake, add virtual first argument process path - argc++; - argv--; - // int version = 0, verbose = 0, width = 0, height = 0; @@ -61,6 +70,7 @@ int cmdline_run(const char **argv, int argc) OPT_HELP(), OPT_BOOLEAN('v', "version", &version, "show version information and exit"), OPT_BOOLEAN(0, "verbose", &verbose, "log verbose messages"), + OPT_INTEGER('m', "mode", &sprite_mode, "the type of sprite conversion. 0 = default, 1 = simple closest pixel match, 2 = dithering"), OPT_END() }; @@ -79,21 +89,9 @@ int cmdline_run(const char **argv, int argc) _log_levels[DIAGNOSTIC_LEVEL_VERBOSE] = 1; if (argc != 0) { - if (_stricmp(argv[0], "intro") == 0) { - gOpenRCT2StartupAction = STARTUP_ACTION_INTRO; - } else if (_stricmp(argv[0], "edit") == 0) { - gOpenRCT2StartupAction = STARTUP_ACTION_EDIT; - if (argc >= 2) - strcpy(gOpenRCT2StartupActionPath, argv[1]); - } else { - if (platform_file_exists(argv[0])) { - gOpenRCT2StartupAction = STARTUP_ACTION_OPEN; - strcpy(gOpenRCT2StartupActionPath, argv[0]); - } else { - fprintf(stderr, "error: %s does not exist\n", argv[0]); - return 0; - } - } + gExitCode = cmdline_call_action(argv, argc); + if (gExitCode != 0) + return 0; } print_launch_information(); @@ -118,4 +116,58 @@ static void print_launch_information() printf("Time: %s\n", buffer); // TODO Print other potential information (e.g. user, hardware) +} + +static int cmdline_for_intro(const char **argv, int argc) +{ + gOpenRCT2StartupAction = STARTUP_ACTION_INTRO; + return 0; +} + +static int cmdline_for_edit(const char **argv, int argc) +{ + gOpenRCT2StartupAction = STARTUP_ACTION_EDIT; + if (argc >= 1) + strcpy(gOpenRCT2StartupActionPath, argv[0]); + + return 0; +} + +static int cmdline_for_none(const char **argv, int argc) +{ + assert(argc >= 1); + + if (platform_file_exists(argv[0])) { + gOpenRCT2StartupAction = STARTUP_ACTION_OPEN; + strcpy(gOpenRCT2StartupActionPath, argv[0]); + return 0; + } else { + fprintf(stderr, "error: %s does not exist\n", argv[0]); + return -1; + } +} + +struct { const char *firstArg; cmdline_action action; } cmdline_table[] = { + { "intro", cmdline_for_intro }, + { "edit", cmdline_for_edit }, + { "sprite", cmdline_for_sprite }, + { "screenshot", cmdline_for_screenshot }, + +#ifdef ENABLE_TESTS + { "test", cmdline_for_test }, +#else + { "test", cmdline_for_test_error }, +#endif +}; + +static int cmdline_call_action(const char **argv, int argc) +{ + for (int i = 0; i < countof(cmdline_table); i++) { + if (_stricmp(cmdline_table[i].firstArg, argv[0]) != 0) + continue; + + return cmdline_table[i].action(argv + 1, argc - 1); + } + + return cmdline_for_none(argv, argc); } \ No newline at end of file diff --git a/src/cmdline.h b/src/cmdline.h index bb046008a0..b86393f047 100644 --- a/src/cmdline.h +++ b/src/cmdline.h @@ -26,6 +26,9 @@ /** The exit code for OpenRCT2 when it exits. */ extern int gExitCode; +int sprite_mode; + int cmdline_run(const char **argv, int argc); +int cmdline_for_sprite(const char **argv, int argc); #endif \ No newline at end of file diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c new file mode 100644 index 0000000000..12691d8709 --- /dev/null +++ b/src/cmdline_sprite.c @@ -0,0 +1,944 @@ +#include +#include +#include "cmdline.h" +#include "drawing/drawing.h" +#include "platform/platform.h" +#include "util/util.h" + +#define MODE_DEFAULT 0 +#define MODE_CLOSEST 1 +#define MODE_DITHERING 2 + +typedef struct { + uint32 num_entries; + uint32 total_size; +} rct_sprite_file_header; + +typedef struct { uint8 b, g, r, a; } rct_sprite_file_palette_entry; + +rct_sprite_file_palette_entry spriteFilePalette[256]; +static rct_sprite_file_palette_entry _standardPalette[256]; + +rct_sprite_file_header spriteFileHeader; +rct_g1_element *spriteFileEntries; +uint8 *spriteFileData; + +void sprite_file_load_palette(int spriteIndex) +{ + rct_g1_element *g1 = &spriteFileEntries[spriteIndex]; + int numPaletteEntries = g1->width; + uint8* src = g1->offset; + rct_sprite_file_palette_entry *destPaletteEntry = &spriteFilePalette[g1->x_offset]; + for (; numPaletteEntries > 0; numPaletteEntries--) { + destPaletteEntry->b = src[0]; + destPaletteEntry->g = src[1]; + destPaletteEntry->r = src[2]; + src += 3; + destPaletteEntry++; + } +} + +void sprite_entries_make_absolute() +{ + for (uint32 i = 0; i < spriteFileHeader.num_entries; i++) + spriteFileEntries[i].offset += (int)spriteFileData; +} + +void sprite_entries_make_relative() +{ + for (uint32 i = 0; i < spriteFileHeader.num_entries; i++) + spriteFileEntries[i].offset -= (int)spriteFileData; +} + +bool sprite_file_open(const char *path) +{ + FILE *file; + + file = fopen(path, "rb"); + if (file == NULL) + return false; + + if (fread(&spriteFileHeader, sizeof(rct_sprite_file_header), 1, file) != 1) { + fclose(file); + return false; + } + + if (spriteFileHeader.num_entries > 0) { + int entryTableSize = spriteFileHeader.num_entries * sizeof(rct_g1_element); + + spriteFileEntries = malloc(entryTableSize); + if (fread(spriteFileEntries, entryTableSize, 1, file) != 1) { + fclose(file); + return false; + } + + spriteFileData = malloc(spriteFileHeader.total_size); + if (fread(spriteFileData, spriteFileHeader.total_size, 1, file) != 1) { + fclose(file); + return false; + } + + sprite_entries_make_absolute(); + } + + fclose(file); + return true; +} + +bool sprite_file_save(const char *path) +{ + FILE *file = fopen(path, "wb"); + if (file == NULL) + return false; + + if (fwrite(&spriteFileHeader, sizeof(rct_sprite_file_header), 1, file) != 1) { + fclose(file); + return false; + } + + if (spriteFileHeader.num_entries > 0) { + sprite_entries_make_relative(); + + int entryTableSize = spriteFileHeader.num_entries * sizeof(rct_g1_element); + + if (fwrite(spriteFileEntries, entryTableSize, 1, file) != 1) { + sprite_entries_make_absolute(); + fclose(file); + return false; + } else { + sprite_entries_make_absolute(); + } + + if (fwrite(spriteFileData, spriteFileHeader.total_size, 1, file) != 1) { + fclose(file); + return false; + } + } + + fclose(file); + return true; +} + +void sprite_file_close() +{ + free(spriteFileEntries); + free(spriteFileData); +} + +bool sprite_file_export(int spriteIndex, const char *outPath) +{ + rct_g1_element *spriteHeader; + rct_drawpixelinfo dpi; + uint8 *pixels; + int pixelBufferSize; + + spriteHeader = &spriteFileEntries[spriteIndex]; + pixelBufferSize = spriteHeader->width * spriteHeader->height; + pixels = malloc(pixelBufferSize); + memset(pixels, 0, pixelBufferSize); + + dpi.bits = pixels; + dpi.x = 0; + dpi.y = 0; + dpi.width = spriteHeader->width; + dpi.height = spriteHeader->height; + dpi.pitch = 0; + dpi.zoom_level = 0; + + memcpy(spriteFilePalette, _standardPalette, 256 * 4); + gfx_rle_sprite_to_buffer(spriteHeader->offset, pixels, (uint8*)spriteFilePalette, &dpi, IMAGE_TYPE_NO_BACKGROUND, 0, spriteHeader->height, 0, spriteHeader->width); + + LodePNGState pngState; + unsigned int pngError; + unsigned char* pngData; + size_t pngSize; + + lodepng_state_init(&pngState); + pngState.info_raw.colortype = LCT_PALETTE; + lodepng_palette_add(&pngState.info_raw, 0, 0, 0, 0); + for (int i = 1; i < 256; i++) { + lodepng_palette_add( + &pngState.info_raw, + spriteFilePalette[i].r, + spriteFilePalette[i].g, + spriteFilePalette[i].b, + 255 + ); + } + + pngError = lodepng_encode(&pngData, &pngSize, pixels, spriteHeader->width, spriteHeader->height, &pngState); + if (pngError != 0) { + fprintf(stderr, "Error creating PNG data, %u: %s", pngError, lodepng_error_text(pngError)); + return false; + } else { + lodepng_save_file(pngData, pngSize, outPath); + free(pngData); + return true; + } +} + +bool is_transparent_pixel(sint16 *colour){ + return colour[3] < 128; +} + +// Returns true if pixel index is an index not used for remapping +bool is_changable_pixel(int palette_index) { + if (palette_index == -1) + return true; + if (palette_index == 0) + return false; + if (palette_index >= 203 && palette_index < 214) + return false; + if (palette_index == 226) + return false; + if (palette_index >= 227 && palette_index < 229) + return false; + if (palette_index >= 243) + return false; + return true; +} + +int get_closest_palette_index(sint16 *colour){ + uint32 smallest_error = -1; + int best_match = -1; + + for (int x = 0; x < 256; x++){ + if (is_changable_pixel(x)){ + uint32 error = + ((sint16)(spriteFilePalette[x].r) - colour[0]) * ((sint16)(spriteFilePalette[x].r) - colour[0]) + + ((sint16)(spriteFilePalette[x].g) - colour[1]) * ((sint16)(spriteFilePalette[x].g) - colour[1]) + + ((sint16)(spriteFilePalette[x].b) - colour[2]) * ((sint16)(spriteFilePalette[x].b) - colour[2]); + + if (smallest_error == -1 || smallest_error > error){ + best_match = x; + smallest_error = error; + } + } + } + return best_match; +} + +int get_palette_index(sint16 *colour) +{ + if (is_transparent_pixel(colour)) + return -1; + + for (int i = 0; i < 256; i++) { + if ((sint16)(spriteFilePalette[i].r) != colour[0]) continue; + if ((sint16)(spriteFilePalette[i].g) != colour[1]) continue; + if ((sint16)(spriteFilePalette[i].b) != colour[2]) continue; + return i; + } + + return -1; +} + +typedef struct { + uint8 num_pixels; + uint8 offset_x; +} rle_code; + +bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength, int mode) +{ + unsigned char *pixels; + unsigned int width, height; + unsigned int pngError; + + memcpy(spriteFilePalette, _standardPalette, 256 * 4); + + pngError = lodepng_decode_file(&pixels, &width, &height, path, LCT_RGBA, 8); + if (pngError != 0) { + fprintf(stderr, "Error creating PNG data, %u: %s", pngError, lodepng_error_text(pngError)); + return false; + } + + if (width > 256 || height > 256) { + fprintf(stderr, "Only images 256x256 or less are supported."); + free(pixels); + return false; + } + + uint8 *buffer = malloc((height * 2) + (width * height * 16)); + uint16 *yOffsets = (uint16*)buffer; + + // A larger range is needed for proper dithering + sint16 *src = malloc(height * width * 4 * 2); + for (uint32 x = 0; x < height * width * 4; x++){ + src[x] = (sint16) pixels[x]; + } + + uint8 *dst = buffer + (height * 2); + + for (unsigned int y = 0; y < height; y++) { + rle_code *previousCode, *currentCode; + + yOffsets[y] = (dst - buffer); + + previousCode = NULL; + currentCode = (rle_code*)dst; + dst += 2; + int startX = 0; + int pixels = 0; + bool pushRun = false; + for (unsigned int x = 0; x < width; x++) { + int paletteIndex = get_palette_index(src); + + if (mode == MODE_CLOSEST || mode == MODE_DITHERING) + if (paletteIndex == -1 && !is_transparent_pixel(src)) + paletteIndex = get_closest_palette_index(src); + + + if (mode == MODE_DITHERING) + if (!is_transparent_pixel(src) && is_changable_pixel(get_palette_index(src))){ + sint16 dr = src[0] - (sint16)(spriteFilePalette[paletteIndex].r); + sint16 dg = src[1] - (sint16)(spriteFilePalette[paletteIndex].g); + sint16 db = src[2] - (sint16)(spriteFilePalette[paletteIndex].b); + + if (x + 1 < width){ + if (!is_transparent_pixel(src + 4) && is_changable_pixel(get_palette_index(src + 4))){ + // Right + src[4] += dr * 7 / 16; + src[5] += dg * 7 / 16; + src[6] += db * 7 / 16; + } + } + + if (y + 1 < height){ + if (x > 0){ + if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(src + 4 * (width - 1)))){ + // Bottom left + src[4 * (width - 1)] += dr * 3 / 16; + src[4 * (width - 1) + 1] += dg * 3 / 16; + src[4 * (width - 1) + 2] += db * 3 / 16; + } + } + + // Bottom + if (!is_transparent_pixel(src + 4 * width) && is_changable_pixel(get_palette_index(src + 4 * width))){ + src[4 * width] += dr * 5 / 16; + src[4 * width + 1] += dg * 5 / 16; + src[4 * width + 2] += db * 5 / 16; + } + + if (x + 1 < width){ + if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(src + 4 * (width + 1)))){ + // Bottom right + src[4 * (width + 1)] += dr * 1 / 16; + src[4 * (width + 1) + 1] += dg * 1 / 16; + src[4 * (width + 1) + 2] += db * 1 / 16; + } + } + } + } + + src += 4; + if (paletteIndex == -1) { + if (pixels != 0) { + x--; + src -= 4; + pushRun = true; + } + } else { + if (pixels == 0) + startX = x; + pixels++; + *dst++ = (uint8)paletteIndex; + } + if (pixels == 127 || x == width - 1) + pushRun = true; + + if (pushRun) { + if (pixels > 0) { + previousCode = currentCode; + currentCode->num_pixels = pixels; + currentCode->offset_x = startX; + + if (x == width - 1) + currentCode->num_pixels |= 0x80; + + currentCode = (rle_code*)dst; + dst += 2; + } else { + if (previousCode == NULL) { + currentCode->num_pixels = 0x80; + currentCode->offset_x = 0; + } else { + previousCode->num_pixels |= 0x80; + dst -= 2; + } + } + startX = 0; + pixels = 0; + pushRun = false; + } + } + } + free(pixels); + + int bufferLength = (int)(dst - buffer); + buffer = realloc(buffer, bufferLength); + + outElement->offset = buffer; + outElement->width = width; + outElement->height = height; + outElement->flags = G1_FLAG_RLE_COMPRESSION; + outElement->x_offset = 0; + outElement->y_offset = 0; + outElement->zoomed_offset = 0; + + *outBuffer = buffer; + *outBufferLength = bufferLength; + return true; +} + +int cmdline_for_sprite(const char **argv, int argc) +{ + if (argc == 0) + return -1; + + if (_strcmpi(argv[0], "details") == 0) { + if (argc < 2) { + fprintf(stderr, "usage: sprite details [idx]\n"); + return -1; + } else if (argc == 2) { + const char *spriteFilePath = argv[1]; + + if (!sprite_file_open(spriteFilePath)) { + fprintf(stderr, "Unable to open input sprite file.\n"); + return -1; + } + + printf("sprites: %d\n", spriteFileHeader.num_entries); + printf("data size: %d\n", spriteFileHeader.total_size); + + sprite_file_close(); + return 1; + } else { + const char *spriteFilePath = argv[1]; + int spriteIndex = atoi(argv[2]); + + if (!sprite_file_open(spriteFilePath)) { + fprintf(stderr, "Unable to open input sprite file.\n"); + return -1; + } + + if (spriteIndex < 0 || spriteIndex >= (int)spriteFileHeader.num_entries) { + sprite_file_close(); + fprintf(stderr, "Sprite #%d does not exist in sprite file.\n", spriteIndex); + return -1; + } + + rct_g1_element *g1 = &spriteFileEntries[spriteIndex]; + printf("width: %d\n", g1->width); + printf("height: %d\n", g1->height); + printf("x offset: %d\n", g1->x_offset); + printf("y offset: %d\n", g1->y_offset); + printf("data offset: 0x%X\n", g1->offset); + + sprite_file_close(); + return 1; + } + } else if (_strcmpi(argv[0], "export") == 0) { + if (argc < 4) { + fprintf(stderr, "usage: sprite export \n"); + return -1; + } + + const char *spriteFilePath = argv[1]; + int spriteIndex = atoi(argv[2]); + const char *outputPath = argv[3]; + + if (!sprite_file_open(spriteFilePath)) { + fprintf(stderr, "Unable to open input sprite file.\n"); + return -1; + } + + if (spriteIndex < 0 || spriteIndex >= (int)spriteFileHeader.num_entries) { + fprintf(stderr, "Sprite #%d does not exist in sprite file.\n", spriteIndex); + return -1; + } + + if (!sprite_file_export(spriteIndex, outputPath)) { + fprintf(stderr, "Could not export\n"); + sprite_file_close(); + return -1; + } + + sprite_file_close(); + return 1; + } else if (_strcmpi(argv[0], "exportall") == 0) { + if (argc < 3) { + fprintf(stderr, "usage: sprite exportall \n"); + return -1; + } + + const char *spriteFilePath = argv[1]; + char outputPath[_MAX_PATH]; + + if (!sprite_file_open(spriteFilePath)) { + fprintf(stderr, "Unable to open input sprite file.\n"); + return -1; + } + + if (!platform_ensure_directory_exists(argv[2])){ + fprintf(stderr, "Unable to create directory.\n"); + return -1; + } + + + int maxIndex = (int)spriteFileHeader.num_entries; + int numbers = (int)floor(log(maxIndex)); + + strncpy(outputPath, argv[2], _MAX_PATH); + int pathLen = strlen(outputPath); + + if (pathLen >= _MAX_PATH - numbers - 5){ + fprintf(stderr, "Path too long.\n"); + return -1; + } + + for (int x = 0; x < numbers; x++){ + outputPath[pathLen + x] = '0'; + } + strncpy(outputPath + pathLen + numbers, ".png", _MAX_PATH); + + for (int spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++){ + + if (spriteIndex % 100 == 99){ + // Status indicator + printf("\r%d / %d, %d%%", spriteIndex, maxIndex, spriteIndex / maxIndex); + } + + // Add to the index at the end of the file name + char *counter = outputPath + pathLen + numbers - 1; + (*counter)++; + while (*counter > '9'){ + *counter = '0'; + counter--; + (*counter)++; + } + + if (!sprite_file_export(spriteIndex, outputPath)) { + fprintf(stderr, "Could not export\n"); + sprite_file_close(); + return -1; + } + } + + sprite_file_close(); + return 1; + + } else if (_strcmpi(argv[0], "create") == 0) { + if (argc < 2) { + fprintf(stderr, "usage: sprite create \n"); + return -1; + } + + const char *spriteFilePath = argv[1]; + + spriteFileHeader.num_entries = 0; + spriteFileHeader.total_size = 0; + sprite_file_save(spriteFilePath); + + sprite_file_close(); + return 1; + } else if (_strcmpi(argv[0], "append") == 0) { + if (argc < 3) { + fprintf(stderr, "usage: sprite append \n"); + return -1; + } + + const char *spriteFilePath = argv[1]; + const char *imagePath = argv[2]; + + rct_g1_element spriteElement; + uint8 *buffer; + int bufferLength; + if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) + return -1; + + if (!sprite_file_open(spriteFilePath)) { + fprintf(stderr, "Unable to open input sprite file.\n"); + return -1; + } + + spriteFileHeader.num_entries++; + spriteFileHeader.total_size += bufferLength; + spriteFileEntries = realloc(spriteFileEntries, spriteFileHeader.num_entries * sizeof(rct_g1_element)); + + sprite_entries_make_relative(); + spriteFileData = realloc(spriteFileData, spriteFileHeader.total_size); + sprite_entries_make_absolute(); + + spriteFileEntries[spriteFileHeader.num_entries - 1] = spriteElement; + memcpy(spriteFileData + (spriteFileHeader.total_size - bufferLength), buffer, bufferLength); + spriteFileEntries[spriteFileHeader.num_entries - 1].offset = spriteFileData + (spriteFileHeader.total_size - bufferLength); + + free(buffer); + if (!sprite_file_save(spriteFilePath)) + return -1; + + return 1; + } else if (_strcmpi(argv[0], "build") == 0) { + if (argc < 3) { + fprintf(stderr, "usage: sprite build [silent]\n"); + return -1; + } + + const char *spriteFilePath = argv[1]; + const char *resourcePath = argv[2]; + char imagePath[MAX_PATH]; + int resourceLength = strlen(resourcePath); + + bool silent = (argc >= 4 && strcmp(argv[3], "silent") == 0); + bool fileExists = true; + FILE *file; + + spriteFileHeader.num_entries = 0; + spriteFileHeader.total_size = 0; + sprite_file_save(spriteFilePath); + + fprintf(stderr, "Building: %s\n", spriteFilePath); + int i = 0; + do { + // Create image path + strcpy(imagePath, resourcePath); + if (resourcePath[resourceLength - 1] == '/' || resourcePath[resourceLength - 1] == '\\') + imagePath[resourceLength - 1] = 0; + sprintf(imagePath, "%s%c%d.png", imagePath, platform_get_path_separator(), i); + + file = fopen(imagePath, "r"); + if (file != NULL) { + fclose(file); + rct_g1_element spriteElement; + uint8 *buffer; + int bufferLength; + if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) { + fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath); + return -1; + } + + if (!sprite_file_open(spriteFilePath)) { + fprintf(stderr, "Unable to open sprite file: %s\nCanceling\n", spriteFilePath); + return -1; + } + + spriteFileHeader.num_entries++; + spriteFileHeader.total_size += bufferLength; + spriteFileEntries = realloc(spriteFileEntries, spriteFileHeader.num_entries * sizeof(rct_g1_element)); + + sprite_entries_make_relative(); + spriteFileData = realloc(spriteFileData, spriteFileHeader.total_size); + sprite_entries_make_absolute(); + + spriteFileEntries[spriteFileHeader.num_entries - 1] = spriteElement; + memcpy(spriteFileData + (spriteFileHeader.total_size - bufferLength), buffer, bufferLength); + spriteFileEntries[spriteFileHeader.num_entries - 1].offset = spriteFileData + (spriteFileHeader.total_size - bufferLength); + + free(buffer); + + if (!sprite_file_save(spriteFilePath)) { + fprintf(stderr, "Could not save sprite file: %s\nCanceling\n", imagePath); + return -1; + } + if (!silent) + fprintf(stderr, "Added: %s\n", imagePath); + } + i++; + } while (file != NULL); + + + fprintf(stderr, "Finished\n", imagePath); + return 1; + } else { + fprintf(stderr, "Unknown sprite command."); + return 1; + } +} + + + +static rct_sprite_file_palette_entry _standardPalette[256] = { + // 0 (unused) + { 0, 0, 0, 255 }, + + // 1 - 9 (misc. e.g. font and water) + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + { 0, 0, 0, 255 }, + + // + { 35, 35, 23, 255 }, + { 51, 51, 35, 255 }, + { 67, 67, 47, 255 }, + { 83, 83, 63, 255 }, + { 99, 99, 75, 255 }, + { 115, 115, 91, 255 }, + { 131, 131, 111, 255 }, + { 151, 151, 131, 255 }, + { 175, 175, 159, 255 }, + { 195, 195, 183, 255 }, + { 219, 219, 211, 255 }, + { 243, 243, 239, 255 }, + { 0, 47, 51, 255 }, + { 0, 59, 63, 255 }, + { 11, 75, 79, 255 }, + { 19, 91, 91, 255 }, + { 31, 107, 107, 255 }, + { 47, 123, 119, 255 }, + { 59, 139, 135, 255 }, + { 79, 155, 151, 255 }, + { 95, 175, 167, 255 }, + { 115, 191, 187, 255 }, + { 139, 207, 203, 255 }, + { 163, 227, 223, 255 }, + { 7, 43, 67, 255 }, + { 11, 59, 87, 255 }, + { 23, 75, 111, 255 }, + { 31, 87, 127, 255 }, + { 39, 99, 143, 255 }, + { 51, 115, 159, 255 }, + { 67, 131, 179, 255 }, + { 87, 151, 191, 255 }, + { 111, 175, 203, 255 }, + { 135, 199, 219, 255 }, + { 163, 219, 231, 255 }, + { 195, 239, 247, 255 }, + { 0, 27, 71, 255 }, + { 0, 43, 95, 255 }, + { 0, 63, 119, 255 }, + { 7, 83, 143, 255 }, + { 7, 111, 167, 255 }, + { 15, 139, 191, 255 }, + { 19, 167, 215, 255 }, + { 27, 203, 243, 255 }, + { 47, 231, 255, 255 }, + { 95, 243, 255, 255 }, + { 143, 251, 255, 255 }, + { 195, 255, 255, 255 }, + { 0, 0, 35, 255 }, + { 0, 0, 79, 255 }, + { 7, 7, 95, 255 }, + { 15, 15, 111, 255 }, + { 27, 27, 127, 255 }, + { 39, 39, 143, 255 }, + { 59, 59, 163, 255 }, + { 79, 79, 179, 255 }, + { 103, 103, 199, 255 }, + { 127, 127, 215, 255 }, + { 159, 159, 235, 255 }, + { 191, 191, 255, 255 }, + { 19, 51, 27, 255 }, + { 23, 63, 35, 255 }, + { 31, 79, 47, 255 }, + { 39, 95, 59, 255 }, + { 43, 111, 71, 255 }, + { 51, 127, 87, 255 }, + { 59, 143, 99, 255 }, + { 67, 155, 115, 255 }, + { 75, 171, 131, 255 }, + { 83, 187, 147, 255 }, + { 95, 203, 163, 255 }, + { 103, 219, 183, 255 }, + { 27, 55, 31, 255 }, + { 35, 71, 47, 255 }, + { 43, 83, 59, 255 }, + { 55, 99, 75, 255 }, + { 67, 111, 91, 255 }, + { 79, 135, 111, 255 }, + { 95, 159, 135, 255 }, + { 111, 183, 159, 255 }, + { 127, 207, 183, 255 }, + { 147, 219, 195, 255 }, + { 167, 231, 207, 255 }, + { 191, 247, 223, 255 }, + { 0, 63, 15, 255 }, + { 0, 83, 19, 255 }, + { 0, 103, 23, 255 }, + { 0, 123, 31, 255 }, + { 7, 143, 39, 255 }, + { 23, 159, 55, 255 }, + { 39, 175, 71, 255 }, + { 63, 191, 91, 255 }, + { 87, 207, 111, 255 }, + { 115, 223, 139, 255 }, + { 143, 239, 163, 255 }, + { 179, 255, 195, 255 }, + { 19, 43, 79, 255 }, + { 27, 55, 99, 255 }, + { 43, 71, 119, 255 }, + { 59, 87, 139, 255 }, + { 67, 99, 167, 255 }, + { 83, 115, 187, 255 }, + { 99, 131, 207, 255 }, + { 115, 151, 215, 255 }, + { 131, 171, 227, 255 }, + { 151, 191, 239, 255 }, + { 171, 207, 247, 255 }, + { 195, 227, 255, 255 }, + { 55, 19, 15, 255 }, + { 87, 43, 39, 255 }, + { 103, 55, 51, 255 }, + { 119, 67, 63, 255 }, + { 139, 83, 83, 255 }, + { 155, 99, 99, 255 }, + { 175, 119, 119, 255 }, + { 191, 139, 139, 255 }, + { 207, 159, 159, 255 }, + { 223, 183, 183, 255 }, + { 239, 211, 211, 255 }, + { 255, 239, 239, 255 }, + { 111, 27, 0, 255 }, + { 151, 39, 0, 255 }, + { 167, 51, 7, 255 }, + { 187, 67, 15, 255 }, + { 203, 83, 27, 255 }, + { 223, 103, 43, 255 }, + { 227, 135, 67, 255 }, + { 231, 163, 91, 255 }, + { 239, 187, 119, 255 }, + { 243, 211, 143, 255 }, + { 251, 231, 175, 255 }, + { 255, 247, 215, 255 }, + { 15, 43, 11, 255 }, + { 23, 55, 15, 255 }, + { 31, 71, 23, 255 }, + { 43, 83, 35, 255 }, + { 59, 99, 47, 255 }, + { 75, 115, 59, 255 }, + { 95, 135, 79, 255 }, + { 119, 155, 99, 255 }, + { 139, 175, 123, 255 }, + { 167, 199, 147, 255 }, + { 195, 219, 175, 255 }, + { 223, 243, 207, 255 }, + { 95, 0, 63, 255 }, + { 115, 7, 75, 255 }, + { 127, 15, 83, 255 }, + { 143, 31, 95, 255 }, + { 155, 43, 107, 255 }, + { 171, 63, 123, 255 }, + { 187, 83, 135, 255 }, + { 199, 103, 155, 255 }, + { 215, 127, 171, 255 }, + { 231, 155, 191, 255 }, + { 243, 195, 215, 255 }, + { 255, 235, 243, 255 }, + { 0, 0, 63, 255 }, + { 0, 0, 87, 255 }, + { 0, 0, 115, 255 }, + { 0, 0, 143, 255 }, + { 0, 0, 171, 255 }, + { 0, 0, 199, 255 }, + { 0, 7, 227, 255 }, + { 0, 7, 255, 255 }, + { 67, 79, 255, 255 }, + { 115, 123, 255, 255 }, + { 163, 171, 255, 255 }, + { 215, 219, 255, 255 }, + { 0, 39, 79, 255 }, + { 0, 51, 111, 255 }, + { 0, 63, 147, 255 }, + { 0, 71, 183, 255 }, + { 0, 79, 219, 255 }, + { 0, 83, 255, 255 }, + { 23, 111, 255, 255 }, + { 51, 139, 255, 255 }, + { 79, 163, 255, 255 }, + { 107, 183, 255, 255 }, + { 135, 203, 255, 255 }, + { 163, 219, 255, 255 }, + { 47, 51, 0, 255 }, + { 55, 63, 0, 255 }, + { 67, 75, 0, 255 }, + { 79, 87, 0, 255 }, + { 99, 107, 7, 255 }, + { 119, 127, 23, 255 }, + { 143, 147, 43, 255 }, + { 163, 167, 71, 255 }, + { 187, 187, 99, 255 }, + { 207, 207, 131, 255 }, + { 231, 231, 171, 255 }, + { 255, 255, 207, 255 }, + + // 203 - 214 (Secondary remap) + { 27, 0, 63, 255 }, + { 51, 0, 103, 255 }, + { 63, 11, 123, 255 }, + { 79, 23, 143, 255 }, + { 95, 31, 163, 255 }, + { 111, 39, 183, 255 }, + { 143, 59, 219, 255 }, + { 171, 91, 239, 255 }, + { 187, 119, 243, 255 }, + { 203, 151, 247, 255 }, + { 223, 183, 251, 255 }, + { 239, 215, 255, 255 }, + + // 214 - 225 (Brown) + { 0, 19, 39, 255 }, + { 7, 31, 55, 255 }, + { 15, 47, 71, 255 }, + { 31, 63, 91, 255 }, + { 51, 83, 107, 255 }, + { 75, 103, 123, 255 }, + { 107, 127, 143, 255 }, + { 127, 147, 163, 255 }, + { 147, 171, 187, 255 }, + { 171, 195, 207, 255 }, + { 195, 219, 231, 255 }, + { 223, 243, 255, 255 }, + + // 226 (unknown) + { 75, 75, 55, 255 }, + + // 227 - 229 (tertiary remap) + { 0, 183, 255, 255 }, + { 0, 219, 255, 255 }, + { 0, 255, 255, 255 }, + + // 230 - 239 (water) + { 99, 107, 7, 255 }, + { 99, 107, 7, 255 }, + { 135, 143, 39, 255 }, + { 123, 131, 27, 255 }, + { 99, 107, 7, 255 }, + { 151, 155, 55, 255 }, + { 151, 155, 55, 255 }, + { 227, 227, 155, 255 }, + { 203, 203, 115, 255 }, + { 151, 155, 55, 255 }, + + // 240 - 242 (chain lift) + { 91, 91, 67, 255 }, + { 107, 107, 83, 255 }, + { 123, 123, 99, 255 }, + + // Old 243 - 245, changed to nice shade remap below + // { 47, 47, 47, 255 }, + // { 47, 47, 47, 255 }, + // { 47, 71, 87, 255 }, + + // 243 to 254 (primary remap) + { 47, 51, 111, 255 }, + { 47, 55, 131, 255 }, + { 51, 63, 151, 255 }, + { 51, 67, 171, 255 }, + { 47, 75, 191, 255 }, + { 43, 79, 211, 255 }, + { 35, 87, 231, 255 }, + { 31, 95, 255, 255 }, + { 39, 127, 255, 255 }, + { 51, 155, 255, 255 }, + { 63, 183, 255, 255 }, + { 75, 207, 255, 255 }, + + // 255 (unused?) + { 0, 0, 0, 255 } +}; diff --git a/src/common.h b/src/common.h index 3fb41aac95..b8c710cf63 100644 --- a/src/common.h +++ b/src/common.h @@ -24,4 +24,6 @@ #include "diagnostic.h" #include "rct2.h" +#define SafeFree(x) if ((x) != NULL) { free(x); (x) = NULL; } + #endif \ No newline at end of file diff --git a/src/config.c b/src/config.c index 7a2b188608..cf7651288e 100644 --- a/src/config.c +++ b/src/config.c @@ -1,36 +1,915 @@ /***************************************************************************** * 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 . *****************************************************************************/ -#include #include "addresses.h" #include "config.h" +#include "localisation/language.h" #include "localisation/localisation.h" -#include "platform/osinterface.h" -#include "platform/platform.h" - -// Current keyboard shortcuts -uint16 gShortcutKeys[SHORTCUT_COUNT]; +#include "util/util.h" +#include "interface/themes.h" +#include "openrct2.h" // Magic number for original game cfg file static const int MagicNumber = 0x0003113A; +enum { + CONFIG_VALUE_TYPE_BOOLEAN, + CONFIG_VALUE_TYPE_UINT8, + CONFIG_VALUE_TYPE_UINT16, + CONFIG_VALUE_TYPE_UINT32, + CONFIG_VALUE_TYPE_SINT8, + CONFIG_VALUE_TYPE_SINT16, + CONFIG_VALUE_TYPE_SINT32, + CONFIG_VALUE_TYPE_FLOAT, + CONFIG_VALUE_TYPE_DOUBLE, + CONFIG_VALUE_TYPE_STRING +}; + +size_t _configValueTypeSize[] = { + sizeof(bool), + sizeof(uint8), + sizeof(uint16), + sizeof(uint32), + sizeof(sint8), + sizeof(sint16), + sizeof(sint32), + sizeof(float), + sizeof(double), + sizeof(utf8string) +}; + +typedef union { + sint32 value_sint32; + + bool value_boolean; + sint8 value_sint8; + sint16 value_sint16; + uint8 value_uint8; + uint16 value_uint16; + uint32 value_uint32; + float value_float; + double value_double; + utf8string value_string; +} value_union; + +typedef struct { + const_utf8string key; + value_union value; +} config_enum_definition; + +#define END_OF_ENUM { NULL, 0 } + +typedef struct { + size_t offset; + const_utf8string property_name; + uint8 type; + value_union default_value; + config_enum_definition *enum_definitions; +} config_property_definition; + +typedef struct { + void *base_address; + const_utf8string section_name; + config_property_definition *property_definitions; + int property_definitions_count; +} config_section_definition; + +#pragma region Enum definitions + +config_enum_definition _screenShotFormatEnum[] = { + { "BMP", SCREENSHOT_FORMAT_BMP }, + { "PNG", SCREENSHOT_FORMAT_PNG }, + END_OF_ENUM +}; + +config_enum_definition _measurementFormatEnum[] = { + { "IMPERIAL", MEASUREMENT_FORMAT_IMPERIAL }, + { "METRIC", MEASUREMENT_FORMAT_METRIC }, + END_OF_ENUM +}; + +config_enum_definition _temperatureFormatEnum[] = { + { "CELSIUS", TEMPERATURE_FORMAT_C }, + { "FAHRENHEIT", TEMPERATURE_FORMAT_F }, + END_OF_ENUM +}; + +config_enum_definition _currencyEnum[] = { + { "GBP", CURRENCY_POUNDS }, + { "USD", CURRENCY_DOLLARS }, + { "FRF", CURRENCY_FRANC }, + { "DEM", CURRENCY_DEUTSCHMARK }, + { "JPY", CURRENCY_YEN }, + { "ESP", CURRENCY_PESETA }, + { "ITL", CURRENCY_LIRA }, + { "NLG", CURRENCY_GUILDERS }, + { "SEK", CURRENCY_KRONA }, + { "EUR", CURRENCY_EUROS }, + END_OF_ENUM +}; + +config_enum_definition _languageEnum[] = { + { "en-GB", LANGUAGE_ENGLISH_UK }, + { "en-US", LANGUAGE_ENGLISH_US }, + { "de-DE", LANGUAGE_GERMAN }, + { "nl-NL", LANGUAGE_DUTCH }, + { "fr-FR", LANGUAGE_FRENCH }, + { "hu-HU", LANGUAGE_HUNGARIAN }, + { "pl-PL", LANGUAGE_POLISH }, + { "es-ES", LANGUAGE_SPANISH }, + { "sv-SE", LANGUAGE_SWEDISH }, + { "it-IT", LANGUAGE_ITALIAN }, + END_OF_ENUM +}; + +config_enum_definition _dateFormatEnum[] = { + { "DD/MM/YY", DATE_FORMAT_DMY }, + { "MM/DD/YY", DATE_FORMAT_MDY }, + END_OF_ENUM +}; + +#pragma endregion + +#pragma region Section / property definitions + +config_property_definition _generalDefinitions[] = { + { offsetof(general_configuration, always_show_gridlines), "always_show_gridlines", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, autosave_frequency), "autosave", CONFIG_VALUE_TYPE_UINT8, AUTOSAVE_EVERY_MONTH, NULL }, + { offsetof(general_configuration, confirmation_prompt), "confirmation_prompt", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, + { offsetof(general_configuration, construction_marker_colour), "construction_marker_colour", CONFIG_VALUE_TYPE_UINT8, false, NULL }, + { offsetof(general_configuration, currency_format), "currency_format", CONFIG_VALUE_TYPE_UINT8, CURRENCY_POUNDS, _currencyEnum }, + { offsetof(general_configuration, edge_scrolling), "edge_scrolling", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(general_configuration, fullscreen_mode), "fullscreen_mode", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, + { offsetof(general_configuration, fullscreen_height), "fullscreen_height", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, + { offsetof(general_configuration, fullscreen_width), "fullscreen_width", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, + { offsetof(general_configuration, game_path), "game_path", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, + { offsetof(general_configuration, landscape_smoothing), "landscape_smoothing", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(general_configuration, language), "language", CONFIG_VALUE_TYPE_UINT16, LANGUAGE_ENGLISH_UK, _languageEnum }, + { offsetof(general_configuration, measurement_format), "measurement_format", CONFIG_VALUE_TYPE_UINT8, MEASUREMENT_FORMAT_IMPERIAL, _measurementFormatEnum }, + { offsetof(general_configuration, play_intro), "play_intro", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, save_plugin_data), "save_plugin_data", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, debugging_tools), "debugging_tools", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, screenshot_format), "screenshot_format", CONFIG_VALUE_TYPE_UINT8, SCREENSHOT_FORMAT_PNG, _screenShotFormatEnum }, + { offsetof(general_configuration, show_height_as_units), "show_height_as_units", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, temperature_format), "temperature_format", CONFIG_VALUE_TYPE_UINT8, TEMPERATURE_FORMAT_C, _temperatureFormatEnum }, + { offsetof(general_configuration, window_height), "window_height", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, + { offsetof(general_configuration, window_snap_proximity), "window_snap_proximity", CONFIG_VALUE_TYPE_UINT8, 5, NULL }, + { offsetof(general_configuration, window_width), "window_width", CONFIG_VALUE_TYPE_SINT32, -1, NULL }, + { offsetof(general_configuration, hardware_display), "hardware_display", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, test_unfinished_tracks), "test_unfinished_tracks", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, no_test_crashes), "no_test_crashes", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, date_format), "date_format", CONFIG_VALUE_TYPE_UINT8, DATE_FORMAT_DMY, _dateFormatEnum }, + { offsetof(general_configuration, auto_staff_placement), "auto_staff", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, last_run_version), "last_run_version", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, + { offsetof(general_configuration, title_sequence), "title_sequence", CONFIG_VALUE_TYPE_UINT8, TITLE_SEQUENCE_OPENRCT2, NULL }, +}; + +config_property_definition _interfaceDefinitions[] = { + { offsetof(interface_configuration, toolbar_show_finances), "toolbar_show_finances", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(interface_configuration, toolbar_show_research), "toolbar_show_research", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(interface_configuration, toolbar_show_cheats), "toolbar_show_cheats", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(interface_configuration, allow_subtype_switching), "allow_subtype_switching", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(interface_configuration, console_small_font), "console_small_font", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(interface_configuration, current_theme_preset), "current_theme", CONFIG_VALUE_TYPE_STRING, { .value_string = "*RCT2" }, NULL }, +}; + +config_property_definition _soundDefinitions[] = { + { offsetof(sound_configuration, title_music), "title_music", CONFIG_VALUE_TYPE_UINT8, 2, NULL }, + { offsetof(sound_configuration, sound), "sound", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(sound_configuration, ride_music), "ride_music", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(sound_configuration, master_volume), "master_volume", CONFIG_VALUE_TYPE_UINT8, 100, NULL }, + { offsetof(sound_configuration, music_volume), "music_volume", CONFIG_VALUE_TYPE_UINT8, 100, NULL }, +}; + +config_property_definition _cheatDefinitions[] = { + { offsetof(cheat_configuration, fast_lift_hill), "fast_lift_hill", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(cheat_configuration, disable_brakes_failure), "disable_brakes_failure", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(cheat_configuration, disable_all_breakdowns), "disable_all_breakdowns", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(cheat_configuration, unlock_all_prices), "unlock_all_prices", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(cheat_configuration, build_in_pause_mode), "build_in_pause_mode", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, +}; + +config_property_definition _twitchDefinitions[] = { + { offsetof(twitch_configuration, channel), "channel", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, + { offsetof(twitch_configuration, enable_follower_peep_names), "follower_peep_names", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(twitch_configuration, enable_follower_peep_tracking), "follower_peep_tracking", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(twitch_configuration, enable_chat_peep_names), "chat_peep_names", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(twitch_configuration, enable_chat_peep_tracking), "chat_peep_tracking", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(twitch_configuration, enable_news), "news", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL } +}; + +config_section_definition _sectionDefinitions[] = { + { &gConfigGeneral, "general", _generalDefinitions, countof(_generalDefinitions) }, + { &gConfigInterface, "interface", _interfaceDefinitions, countof(_interfaceDefinitions) }, + { &gConfigSound, "sound", _soundDefinitions, countof(_soundDefinitions) }, + { &gConfigCheat, "cheat", _cheatDefinitions, countof(_cheatDefinitions) }, + { &gConfigTwitch, "twitch", _twitchDefinitions, countof(_twitchDefinitions) } +}; + +#pragma endregion + +general_configuration gConfigGeneral; +interface_configuration gConfigInterface; +sound_configuration gConfigSound; +cheat_configuration gConfigCheat; +twitch_configuration gConfigTwitch; +themes_configuration gConfigThemes; + +bool config_open(const utf8string path); +bool config_save(const utf8string path); +static void config_read_properties(config_section_definition **currentSection, const_utf8string line); +static void config_save_property_value(FILE *file, uint8 type, value_union *value); +static bool config_read_enum(void *dest, int destSize, const utf8 *key, int keySize, config_enum_definition *enumDefinitions); +static void config_write_enum(FILE *file, uint8 type, value_union *value, config_enum_definition *enumDefinitions); + +static int utf8_read(utf8 **outch); +static void utf8_skip_whitespace(utf8 **outch); +static void utf8_skip_non_whitespace(utf8 **outch); + +void config_apply_to_old_addresses(); + +void config_set_defaults() +{ + int i, j; + + for (i = 0; i < countof(_sectionDefinitions); i++) { + config_section_definition *section = &_sectionDefinitions[i]; + for (j = 0; j < section->property_definitions_count; j++) { + config_property_definition *property = §ion->property_definitions[j]; + + value_union *destValue = (value_union*)((size_t)section->base_address + (size_t)property->offset); + + if (strcmp(property->property_name, "language") == 0){ + destValue->value_uint16 = platform_get_locale_language(); + if (destValue->value_uint16 == LANGUAGE_UNDEFINED) + memcpy(destValue, &property->default_value, _configValueTypeSize[property->type]); + } + else if (strcmp(property->property_name, "currency_format") == 0){ + destValue->value_uint8 = platform_get_locale_currency(); + } + else if (strcmp(property->property_name, "measurement_format") == 0){ + destValue->value_uint8 = platform_get_locale_measurement_format(); + } + else if (strcmp(property->property_name, "temperature_format") == 0){ + destValue->value_uint8 = platform_get_locale_temperature_format(); + } + else { + memcpy(destValue, &property->default_value, _configValueTypeSize[property->type]); + } + } + } +} + +bool config_open_default() +{ + utf8 path[MAX_PATH]; + + platform_get_user_directory(path, NULL); + strcat(path, "config.ini"); + if (config_open(path)) { + config_apply_to_old_addresses(); + return true; + } + + return false; +} + +bool config_save_default() +{ + utf8 path[MAX_PATH]; + + platform_get_user_directory(path, NULL); + strcat(path, "config.ini"); + if (config_save(path)) { + config_apply_to_old_addresses(); + return true; + } + + return false; +} + +bool config_open(const utf8string path) +{ + FILE *file; + uint8 *lineBuffer; + size_t lineBufferCapacity; + size_t lineLength; + int c; + config_section_definition *currentSection; + + file = fopen(path, "rb"); + if (file == NULL) + return false; + + currentSection = NULL; + lineBufferCapacity = 64; + lineBuffer = malloc(lineBufferCapacity); + lineLength = 0; + + // Skim UTF-8 byte order mark + fread(lineBuffer, 3, 1, file); + if (!utf8_is_bom(lineBuffer)) + fseek(file, 0, SEEK_SET); + + while ((c = fgetc(file)) != EOF) { + if (c == '\n' || c == '\r') { + lineBuffer[lineLength++] = 0; + config_read_properties(¤tSection, (const_utf8string)lineBuffer); + lineLength = 0; + } else { + lineBuffer[lineLength++] = c; + } + + if (lineLength >= lineBufferCapacity) { + lineBufferCapacity *= 2; + lineBuffer = realloc(lineBuffer, lineBufferCapacity); + } + } + + if (lineLength > 0) { + lineBuffer[lineLength++] = 0; + config_read_properties(¤tSection, lineBuffer); + } + + free(lineBuffer); + fclose(file); + return true; +} + +bool config_save(const utf8string path) +{ + FILE *file; + int i, j; + value_union *value; + + file = fopen(path, "wb"); + if (file == NULL) { + log_error("Unable to write to config file."); + return false; + } + + for (i = 0; i < countof(_sectionDefinitions); i++) { + config_section_definition *section = &_sectionDefinitions[i]; + + fputc('[', file); + fwrite(section->section_name, strlen(section->section_name), 1, file); + fputc(']', file); + fputc('\n', file); + + for (j = 0; j < section->property_definitions_count; j++) { + config_property_definition *property = §ion->property_definitions[j]; + + fwrite(property->property_name, strlen(property->property_name), 1, file); + fwrite(" = ", 3, 1, file); + + value = (value_union*)((size_t)section->base_address + (size_t)property->offset); + if (property->enum_definitions != NULL) + config_write_enum(file, property->type, value, property->enum_definitions); + else + config_save_property_value(file, property->type, value); + fputc('\n', file); + } + fputc('\n', file); + } + + fclose(file); + return true; +} + +static void config_save_property_value(FILE *file, uint8 type, value_union *value) +{ + switch (type) { + case CONFIG_VALUE_TYPE_BOOLEAN: + if (value->value_boolean) fwrite("true", 4, 1, file); + else fwrite("false", 5, 1, file); + break; + case CONFIG_VALUE_TYPE_UINT8: + fprintf(file, "%u", value->value_uint8); + break; + case CONFIG_VALUE_TYPE_UINT16: + fprintf(file, "%u", value->value_uint16); + break; + case CONFIG_VALUE_TYPE_UINT32: + fprintf(file, "%u", value->value_uint32); + break; + case CONFIG_VALUE_TYPE_SINT8: + fprintf(file, "%d", value->value_sint8); + break; + case CONFIG_VALUE_TYPE_SINT16: + fprintf(file, "%d", value->value_sint16); + break; + case CONFIG_VALUE_TYPE_SINT32: + fprintf(file, "%d", value->value_sint32); + break; + case CONFIG_VALUE_TYPE_FLOAT: + fprintf(file, "%.3f", value->value_float); + break; + case CONFIG_VALUE_TYPE_DOUBLE: + fprintf(file, "%.6f", value->value_double); + break; + case CONFIG_VALUE_TYPE_STRING: + fputc('"', file); + if (value->value_string != NULL) + fwrite(value->value_string, strlen(value->value_string), 1, file); + fputc('"', file); + break; + } +} + +bool config_get_section(const utf8string line, const utf8 **sectionName, int *sectionNameSize) +{ + utf8 *ch; + int c; + + ch = line; + utf8_skip_whitespace(&ch); + if (*ch != '[') return false; + *sectionName = ++ch; + + while (*ch != 0) { + c = utf8_read(&ch); + if (c == '#') return false; + if (c == '[') return false; + if (c == ' ') break; + if (c == ']') break; + } + + *sectionNameSize = ch - *sectionName - 1; + return true; +} + +bool config_get_property_name_value(const utf8string line, utf8 **propertyName, int *propertyNameSize, utf8 **value, int *valueSize) +{ + utf8 *ch; + int c, lastC; + bool quotes; + + ch = line; + utf8_skip_whitespace(&ch); + + if (*ch == 0) return false; + *propertyName = ch; + + while (*ch != 0) { + c = utf8_read(&ch); + if (isspace(c) || c == '=') { + *propertyNameSize = ch - *propertyName - 1; + break; + } else if (c == '#') { + return false; + } + } + + if (*ch == 0) return false; + utf8_skip_whitespace(&ch); + if (*ch != '=') return false; + ch++; + utf8_skip_whitespace(&ch); + if (*ch == 0) return false; + + if (*ch == '"') { + ch++; + quotes = true; + } else { + quotes = false; + } + *value = ch; + + while (*ch != 0) { + c = utf8_read(&ch); + if (isspace(c) || c == '#') { + if (!quotes) break; + } + lastC = c; + } + *valueSize = ch - *value - 1; + return true; +} + +config_section_definition *config_get_section_def(const utf8 *name, int size) +{ + int i; + + for (i = 0; i < countof(_sectionDefinitions); i++) { + const_utf8string sectionName = _sectionDefinitions[i].section_name; + if (sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0) + return &_sectionDefinitions[i]; + } + + return NULL; +} + +config_property_definition *config_get_property_def(config_section_definition *section, const utf8 *name, int size) +{ + int i; + + for (i = 0; i < section->property_definitions_count; i++) { + const_utf8string propertyName = section->property_definitions[i].property_name; + if (propertyName[size] == 0 && _strnicmp(propertyName, name, size) == 0) + return §ion->property_definitions[i]; + } + + return NULL; +} + +void config_set_property(const config_section_definition *section, const config_property_definition *property, const utf8 *value, int valueSize) +{ + value_union *destValue = (value_union*)((size_t)section->base_address + (size_t)property->offset); + + if (property->enum_definitions != NULL) + if (config_read_enum(destValue, _configValueTypeSize[property->type], value, valueSize, property->enum_definitions)) + return; + + switch (property->type) { + case CONFIG_VALUE_TYPE_BOOLEAN: + if (_strnicmp(value, "false", valueSize) == 0) destValue->value_boolean = false; + else if (_strnicmp(value, "true", valueSize) == 0) destValue->value_boolean = true; + else destValue->value_boolean = strtol(value, NULL, 0) != 0; + break; + case CONFIG_VALUE_TYPE_UINT8: + destValue->value_uint8 = (uint8)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_UINT16: + destValue->value_uint16 = (uint16)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_UINT32: + destValue->value_uint32 = (uint32)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_SINT8: + destValue->value_sint8 = (sint8)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_SINT16: + destValue->value_sint16 = (sint16)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_SINT32: + destValue->value_sint32 = (sint32)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_FLOAT: + destValue->value_float = strtof(value, NULL); + break; + case CONFIG_VALUE_TYPE_DOUBLE: + destValue->value_double = strtod(value, NULL); + break; + case CONFIG_VALUE_TYPE_STRING: + SafeFree(destValue->value_string); + destValue->value_string = malloc(valueSize + 1); + memcpy(destValue->value_string, value, valueSize); + destValue->value_string[valueSize] = 0; + break; + } +} + +static void config_read_properties(config_section_definition **currentSection, const_utf8string line) +{ + utf8 *ch = (utf8*)line; + utf8_skip_whitespace(&ch); + + if (*ch == '[') { + const utf8 *sectionName; + int sectionNameSize; + if (config_get_section(ch, §ionName, §ionNameSize)) + *currentSection = config_get_section_def(sectionName, sectionNameSize); + } else { + if (*currentSection != NULL) { + utf8 *propertyName, *value; + int propertyNameSize, valueSize; + if (config_get_property_name_value(ch, &propertyName, &propertyNameSize, &value, &valueSize)) { + config_property_definition *property; + property = config_get_property_def(*currentSection, propertyName, propertyNameSize); + if (property != NULL) + config_set_property(*currentSection, property, value, valueSize); + } + } + } +} + +static bool config_read_enum(void *dest, int destSize, const utf8 *key, int keySize, config_enum_definition *enumDefinitions) +{ + while (enumDefinitions->key != NULL) { + if (_strnicmp(enumDefinitions->key, key, keySize) == 0) { + memcpy(dest, &enumDefinitions->value.value_uint32, destSize); + return true; + } + enumDefinitions++; + } + return false; +} + +static void config_write_enum(FILE *file, uint8 type, value_union *value, config_enum_definition *enumDefinitions) +{ + uint32 enumValue = (value->value_uint32) & ((1 << (_configValueTypeSize[type] * 8)) - 1); + while (enumDefinitions->key != NULL) { + if (enumDefinitions->value.value_uint32 == enumValue) { + fwrite(enumDefinitions->key, strlen(enumDefinitions->key), 1, file); + return; + } + enumDefinitions++; + } + config_save_property_value(file, type, value); +} + +static int utf8_read(utf8 **outch) +{ + int result; + int numBytes; + + utf8 *ch = *outch; + if (!(ch[0] & 0x80)) { + result = ch[0]; + numBytes = 1; + } else if (!(ch[0] & 0x20)) { + result = ((ch[0] & 0x1F) << 6) | (ch[1] & 0x3F); + numBytes = 2; + } else { + numBytes = 1; + } + + *outch = ch + numBytes; + return result; +} + +static void utf8_skip_whitespace(utf8 **outch) +{ + utf8 *ch; + while (**outch != 0) { + ch = *outch; + if (!isspace(utf8_read(outch))) { + *outch = ch; + break; + } + } +} + +static void utf8_skip_non_whitespace(utf8 **outch) +{ + while (**outch != 0) { + if (isspace(utf8_read(outch))) + break; + } +} + +/* + +Code reserved for when we want more intelligent saving of config file which preserves comments and layout + +enum { + CONFIG_LINE_TYPE_WHITESPACE, + CONFIG_LINE_TYPE_COMMENT, + CONFIG_LINE_TYPE_SECTION, + CONFIG_LINE_TYPE_PROPERTY, + CONFIG_LINE_TYPE_INVALID +}; + +typedef struct { + uint8 type; + utf8string line; +} config_line; + +static config_line *_configLines = NULL; + +*/ + +/** + * Attempts to find the RCT2 installation directory. + * This should be created from some other resource when OpenRCT2 grows. + * @param resultPath Pointer to where the absolute path of the RCT2 installation directory will be copied to. + * @returns 1 if successful, otherwise 0. + */ +static bool config_find_rct2_path(char *resultPath) +{ + int i; + + log_verbose("searching common installation locations."); + + const char *searchLocations[] = { + "C:\\Program Files\\Infogrames\\RollerCoaster Tycoon 2", + "C:\\Program Files (x86)\\Infogrames\\RollerCoaster Tycoon 2", + "C:\\Program Files\\Infogrames Interactive\\RollerCoaster Tycoon 2", + "C:\\Program Files (x86)\\Infogrames Interactive\\RollerCoaster Tycoon 2", + "C:\\Program Files\\Atari\\RollerCoaster Tycoon 2", + "C:\\Program Files (x86)\\Atari\\RollerCoaster Tycoon 2", + "C:\\GOG Games\\RollerCoaster Tycoon 2 Triple Thrill Pack", + gExePath + }; + + for (i = 0; i < countof(searchLocations); i++) { + if (platform_directory_exists(searchLocations[i]) ) { + strcpy(resultPath, searchLocations[i]); + return true; + } + } + + return false; +} + +bool config_find_or_browse_install_directory() +{ + char path[MAX_PATH]; + char *installPath; + + if (config_find_rct2_path(path)) { + SafeFree(gConfigGeneral.game_path); + gConfigGeneral.game_path = malloc(strlen(path) + 1); + strcpy(gConfigGeneral.game_path, path); + } else { + platform_show_messagebox("Unable to find RCT2 installation directory. Please select the directory where you installed RCT2!"); + installPath = platform_open_directory_browser("Please select your RCT2 directory"); + if (installPath == NULL) + return false; + + SafeFree(gConfigGeneral.game_path); + gConfigGeneral.game_path = installPath; + } + + return true; +} + +#pragma region Obsolete + +/** + * Any code not implemented in OpenRCT2 will still uses the old configuration option addresses. This function copies all the + * OpenRCT2 configuration options to those addresses until the process is no longer necessary. + */ +void config_apply_to_old_addresses() +{ + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, sint8) = gConfigGeneral.edge_scrolling; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, sint8) = gConfigGeneral.currency_format; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) = gConfigGeneral.measurement_format; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, sint8) = gConfigGeneral.temperature_format; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8) = gConfigGeneral.construction_marker_colour; + // Force best sound quality and software buffering, for original code. + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 2; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, sint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (gConfigGeneral.measurement_format + 1) * 256; + if (gConfigGeneral.show_height_as_units) + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = 0; + + int configFlags = 0; + if (gConfigGeneral.always_show_gridlines) + configFlags |= CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES; + if (!gConfigGeneral.landscape_smoothing) + configFlags |= CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE; + if (gConfigGeneral.show_height_as_units) + configFlags |= CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; + if (gConfigGeneral.save_plugin_data) + configFlags |= CONFIG_FLAG_SAVE_PLUGIN_DATA; + + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) = configFlags; +} + +// The following functions are related to the original configuration file. This has now been replaced with a new configuration +// INI file located in the user's OpenRCT2 home directory. + +/** + * Reads the config file data/config.cfg + * rct2: 0x006752D5 + */ +void config_dat_load() +{ + FILE *fp=NULL; + + const char *path = get_file_path(PATH_ID_GAMECFG); + + fp = fopen(path, "rb"); + + if (fp != NULL) { + // Read and check magic number + fread(RCT2_ADDRESS(0x013CE928, void), 1, 4, fp); + + if (RCT2_GLOBAL(0x013CE928, int) == MagicNumber) { + // Read options + fread((void*)0x009AAC5C, 1, 2155, fp); + fclose(fp); + + //general configuration + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, sint8) = gConfigGeneral.edge_scrolling; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, sint8) = gConfigGeneral.currency_format; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) = gConfigGeneral.measurement_format; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, sint8) = gConfigGeneral.temperature_format; + + // always show gridlines + if (gConfigGeneral.always_show_gridlines){ + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES; + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES; + } + + // landscape smoothing + if (!gConfigGeneral.landscape_smoothing){ + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE; + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE; + } + + // show height as units + if (gConfigGeneral.show_height_as_units){ + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; + } + + // save plugin data + if (gConfigGeneral.save_plugin_data){ + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_SAVE_PLUGIN_DATA; + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_SAVE_PLUGIN_DATA; + } + + //sound configuration: force software buffering and best quality + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 2; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, sint8) = 1; + + // Line below is temporaraly disabled until all config is in the new format. + //if (RCT2_GLOBAL(0x009AB4C6, sint8) == 1) + // return; + + + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_CONFIG, sint8) = 1; // Marks config as first time loaded + + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 2) * 256; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 1) * 256; + // No longer used (controls first time object load) + //RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_OBJECTS, sint8) = 0; + } + + } + + /* TODO: CLEANUP + + if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_CONFIG, sint8) == 1) + return; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_CONFIG, sint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, sint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, sint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = 0; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 1) * 256; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_OBJECTS, sint8) = 1; + } + + } + + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_MEM_TOTAL_PHYSICAL, uint32) > 0x4000000) { + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_MEM_TOTAL_PHYSICAL, uint32) > 0x8000000) + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 2; + } + */ + + + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MAX_VEHICLE_SOUNDS, sint8) = RCT2_ADDRESS(0x009AF601, sint8)[RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8)]; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MAX_NO_SOUNDS, sint8) = RCT2_ADDRESS(0x009AF604, sint8)[RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8)]; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = 0; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 1) * 256; + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_OBJECTS, sint8) = 1; +} + +/** + * Save configuration to the data/config.cfg file + * rct2: 0x00675487 + */ +void config_dat_save() +{ + FILE *fp = fopen(get_file_path(PATH_ID_GAMECFG), "wb"); + if (fp != NULL){ + fwrite(&MagicNumber, 4, 1, fp); + fwrite((void*)0x009AAC5C, 2155, 1, fp); + fclose(fp); + } +} + +#pragma endregion + +#pragma region Shortcuts + +// Current keyboard shortcuts +uint16 gShortcutKeys[SHORTCUT_COUNT]; + // Default keyboard shortcuts static const uint16 _defaultShortcutKeys[SHORTCUT_COUNT] = { SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_TOP_MOST_WINDOW @@ -72,45 +951,6 @@ static const uint16 _defaultShortcutKeys[SHORTCUT_COUNT] = { 0x0200 | 0x0400 | SDL_SCANCODE_C // SHORTCUT_OPEN_CHEAT_WINDOW, }; -general_configuration_t gGeneral_config; -general_configuration_t gGeneral_config_default = { - 0, // play_intro - 0, // confirmation_prompt - SCREENSHOT_FORMAT_PNG, // screenshot_format - "", // game_path - MEASUREMENT_FORMAT_IMPERIAL, // measurement_format - TEMPERATURE_FORMAT_C, // temperature_format - CURRENCY_POUNDS, // currency_format - 0, // construction_marker_colour - 1, // edge_scrolling - 0, // always_show_gridlines - 1, // landscape_smoothing - 0, // show_height_as_units - 1, // save_plugin_data - 0, // fullscreen mode (default: windowed) - -1, // window_width - -1, // window_height - LANGUAGE_ENGLISH_UK, // language - 5 // window_snap_proximity -}; -sound_configuration_t gSound_config; - -static char *config_show_directory_browser(); -static void config_parse_settings(FILE *fp); -static void config_general(char *setting, char *value); -static void config_sound(char *setting, char *value); -static int config_get_line(FILE *fp, char *setting, char *value); -static int config_parse_setting(FILE *fp, char *setting); -static int config_parse_value(FILE *fp, char *value); -static int config_parse_section(FILE *fp, char *setting, char *value); -static void config_create_default(char *path); -static int config_parse_currency(char* currency); -static void config_error(char *msg); - -void config_save_ini(char *path); -void config_write_ini_general(FILE *fp); -void config_write_ini_sound(FILE *fp); - /** * * rct2: 0x006E3604 @@ -120,776 +960,439 @@ void config_reset_shortcut_keys() memcpy(gShortcutKeys, _defaultShortcutKeys, sizeof(gShortcutKeys)); } -void config_save_ini(char *path) +void config_shortcut_keys_get_path(char *outPath) { - FILE *fp = NULL; - - - fp = fopen(path, "wt+"); - - config_write_ini_general(fp); - config_write_ini_sound(fp); - - fclose(fp); + platform_get_user_directory(outPath, NULL); + strcat(outPath, "hotkeys.cfg"); } -void config_write_ini_sound(FILE *fp) +bool config_shortcut_keys_load() { - fprintf(fp, "[sound]\n"); - if (gSound_config.sound_quality == SOUND_QUALITY_LOW) { - fprintf(fp, "sound_quality = low\n"); - } - else if (gSound_config.sound_quality == SOUND_QUALITY_MEDIUM) { - fprintf(fp, "sound_quality = medium\n"); - } - else{ - fprintf(fp, "sound_quality = high\n"); - } - - if (gSound_config.forced_software_buffering){ - fprintf(fp, "forced_software_buffering = true\n"); - } - else { - fprintf(fp, "forced_software_buffering = false\n"); + char path[MAX_PATH]; + FILE *file; + int result; + + config_shortcut_keys_get_path(path); + + file = fopen(path, "rb"); + if (file != NULL) { + result = fread(gShortcutKeys, sizeof(gShortcutKeys), 1, file) == 1; + fclose(file); + } else { + result = false; } + + return result; } -void config_write_ini_general(FILE *fp) +bool config_shortcut_keys_save() { - int currencyIterator = 0; + char path[MAX_PATH]; + FILE *file; + int result; - fprintf(fp, "[general]\n"); - fprintf(fp, "game_path = %s\n", gGeneral_config.game_path); + config_shortcut_keys_get_path(path); - switch (gGeneral_config.screenshot_format) - { - case SCREENSHOT_FORMAT_BMP: - fprintf(fp, "screenshot_format = BMP\n"); - break; - case SCREENSHOT_FORMAT_PNG: - fprintf(fp, "screenshot_format = PNG\n"); - break; - default: - config_error("error saving config.ini: wrong screenshot_format"); - break; + file = fopen(path, "wb"); + if (file != NULL) { + result = fwrite(gShortcutKeys, sizeof(gShortcutKeys), 1, file) == 1; + fclose(file); + } else { + result = false; } - if (gGeneral_config.play_intro){ - fprintf(fp, "play_intro = true\n"); - } - else { - fprintf(fp, "play_intro = false\n"); + return result; +} + +#pragma endregion + + +#pragma region Themes + +typedef struct { + size_t offset; + const_utf8string property_name; + uint8 type; + value_union default_value; + config_enum_definition *enum_definitions; +} theme_property_definition; + +typedef struct { + size_t offset; + const_utf8string section_name; + theme_property_definition *property_definitions; + int property_definitions_count; +} theme_section_definition; + + +theme_property_definition _themeWindowDefinitions[] = { + { offsetof(theme_window, colours[0]), "colour_0", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, + { offsetof(theme_window, colours[1]), "colour_1", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, + { offsetof(theme_window, colours[2]), "colour_2", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, + { offsetof(theme_window, colours[3]), "colour_3", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, + { offsetof(theme_window, colours[4]), "colour_4", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, + { offsetof(theme_window, colours[5]), "colour_5", CONFIG_VALUE_TYPE_UINT8, 0, NULL }, +}; + +theme_property_definition _themeFeaturesDefinitions[] = { + { offsetof(theme_features, rct1_ride_lights), "rct1_ride_lights", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(theme_features, rct1_park_lights), "rct1_park_lights", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(theme_features, rct1_scenario_font), "rct1_scenario_font", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, +}; + + +theme_section_definition _themeSectionDefinitions[] = { + // Special definition for theme windows + { 0, "", _themeWindowDefinitions, countof(_themeWindowDefinitions) }, + { offsetof(theme_preset, features), "features", _themeFeaturesDefinitions, countof(_themeFeaturesDefinitions) }, +}; + +static bool themes_open(const_utf8string path); +static bool themes_save(const_utf8string path, int preset); +static void themes_read_properties(theme_preset *theme, theme_section_definition **currentSection, utf8string line); +static void themes_set_property(theme_preset *theme, const theme_section_definition *section, const theme_property_definition *property, utf8string value, int valueSize); +static theme_section_definition* themes_get_section_def(utf8string name, int size); +static theme_property_definition *themes_get_property_def(theme_section_definition *section, utf8string name, int size); + +void themes_set_default() +{ + utf8 path[MAX_PATH]; + + platform_get_user_directory(path, "themes"); + platform_ensure_directory_exists(path); + + gConfigThemes.num_presets = 2; + gConfigThemes.presets = malloc(sizeof(theme_preset) * gConfigThemes.num_presets); + + // Set RCT2 theme + strcpy(gConfigThemes.presets[0].name, language_get_string(2741)); + gConfigThemes.presets[0].windows = malloc(sizeof(theme_window) * gNumThemeWindows); + + // Define the defaults for RCT2 here + gConfigThemes.presets[0].features.rct1_ride_lights = false; + gConfigThemes.presets[0].features.rct1_park_lights = false; + gConfigThemes.presets[0].features.rct1_scenario_font = false; + + + for (int i = 0; i < (int)gNumThemeWindows; i++) { + gConfigThemes.presets[0].windows[i] = gThemeWindowDefinitions[i].window; } - if (gGeneral_config.confirmation_prompt){ - fprintf(fp, "confirmation_prompt = true\n"); - } - else { - fprintf(fp, "confirmation_prompt = false\n"); - } + // Set RCT1 theme + strcpy(gConfigThemes.presets[1].name, language_get_string(2740)); + gConfigThemes.presets[1].windows = malloc(sizeof(theme_window) * gNumThemeWindows); - if (gGeneral_config.edge_scrolling){ - fprintf(fp, "edge_scrolling = true\n"); - } - else { - fprintf(fp, "edge_scrolling = false\n"); - } + // Define the defaults for RCT1 here + gConfigThemes.presets[1].features.rct1_ride_lights = true; + gConfigThemes.presets[1].features.rct1_park_lights = true; + gConfigThemes.presets[1].features.rct1_scenario_font = true; - for (currencyIterator = 0; currencyIterator < countof(_currencyLookupTable); currencyIterator++) { - if (_currencyLookupTable[currencyIterator].value == gGeneral_config.currency_format) { - gGeneral_config.currency_format = _currencyLookupTable[currencyIterator].value; - fprintf(fp, "currency = %s\n", _currencyLookupTable[currencyIterator].key); - break; // There are more than one valid item for Pound, Euro and Dollar ... + + for (int i = 0; i < (int)gNumThemeWindows; i++) { + uint8 changed_colour = 0xFF; + for (int k = 0; gThemeWindowsRCT1[k].classification != 0xFF; k++) { + if (gThemeWindowsRCT1[k].classification == gThemeWindowDefinitions[i].classification) { + changed_colour = (uint8)k; + break; + } + } + gConfigThemes.presets[1].windows[i] = (changed_colour != 0xFF ? gThemeWindowsRCT1[changed_colour].window : gThemeWindowDefinitions[i].window); } } - if (gGeneral_config.measurement_format == MEASUREMENT_FORMAT_IMPERIAL) { - fprintf(fp, "measurement_format = imperial\n"); - } - else { - fprintf(fp, "measurement_format = metric\n"); - } - - if (gGeneral_config.temperature_format == TEMPERATURE_FORMAT_F) { - fprintf(fp, "temperature_format = fahrenheit\n"); - } - else { - fprintf(fp, "temperature_format = celsius\n"); - } - - if (gGeneral_config.always_show_gridlines){ - fprintf(fp, "always_show_gridlines = true\n"); - } - else { - fprintf(fp, "always_show_gridlines = false\n"); - } - - if (gGeneral_config.landscape_smoothing){ - fprintf(fp, "landscape_smoothing = true\n"); - } - else { - fprintf(fp, "landscape_smoothing = false\n"); - } - - if (gGeneral_config.show_height_as_units){ - fprintf(fp, "show_height_as_units = true\n"); - } - else { - fprintf(fp, "show_height_as_units = false\n"); - } - - if (gGeneral_config.save_plugin_data){ - fprintf(fp, "save_plugin_data = true\n"); - } - else { - fprintf(fp, "save_plugin_data = false\n"); - } - - if (gGeneral_config.fullscreen_mode == 0) - fprintf(fp, "fullscreen_mode = window\n"); - else if (gGeneral_config.fullscreen_mode == 1) - fprintf(fp, "fullscreen_mode = fullscreen\n"); - else - fprintf(fp, "fullscreen_mode = borderless_fullscreen\n"); - - if (gGeneral_config.window_width != -1) - fprintf(fp, "window_width = %d\n", gGeneral_config.window_width); - if (gGeneral_config.window_height != -1) - fprintf(fp, "window_height = %d\n", gGeneral_config.window_height); - - fprintf(fp, "language = %d\n", gGeneral_config.language); - - fprintf(fp, "window_snap_proximity = %d\n", gGeneral_config.window_snap_proximity); -} - -/** - * Any code not implemented in OpenRCT2 will still uses the old configuration option addresses. This function copies all the - * OpenRCT2 configuration options to those addresses until the process is no longer necessary. - */ -void config_apply_to_old_addresses() +void themes_load_presets() { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, sint8) = gGeneral_config.edge_scrolling; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, sint8) = gGeneral_config.currency_format; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) = gGeneral_config.measurement_format; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, sint8) = gGeneral_config.temperature_format; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8) = gGeneral_config.construction_marker_colour; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = gSound_config.sound_quality; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, sint8) = gSound_config.forced_software_buffering; + utf8 path[MAX_PATH]; + file_info file; + int fileEnumHandle, i; - int configFlags = 0; - if (gGeneral_config.always_show_gridlines) - configFlags |= CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES; - if (!gGeneral_config.landscape_smoothing) - configFlags |= CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE; - if (gGeneral_config.show_height_as_units) - configFlags |= CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; - if (gGeneral_config.save_plugin_data) - configFlags |= CONFIG_FLAG_SAVE_PLUGIN_DATA; + platform_get_user_directory(path, "themes"); + strcat(path, "*.ini"); + fileEnumHandle = platform_enumerate_files_begin(path); + while (platform_enumerate_files_next(fileEnumHandle, &file)) { + platform_get_user_directory(path, "themes"); + strcat(path, file.path); + themes_open(path); + } + platform_enumerate_files_end(fileEnumHandle); - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) = configFlags; + if (strcmp(gConfigInterface.current_theme_preset, "*RCT2") == 0) { + theme_change_preset(0); + } + else if (strcmp(gConfigInterface.current_theme_preset, "*RCT1") == 0) { + theme_change_preset(1); + } + else { + for (i = 2; i < gConfigThemes.num_presets; i++) { + if (strcmp(gConfigInterface.current_theme_preset, gConfigThemes.presets[i].name) == 0) { + theme_change_preset(i); + break; + } + } + if (i == gConfigThemes.num_presets) { + theme_change_preset(0); + } + } } -/** - * Initialise the settings. - * It checks if the OpenRCT2 folder exists and creates it if it does not - * parsing of the config file is done in config_parse_settings - */ -void config_load() -{ - char *path = osinterface_get_orct2_homefolder(); - FILE* fp; +bool themes_save_preset(int preset) +{ + utf8 path[MAX_PATH]; + + platform_get_user_directory(path, "themes"); + strcat(path, gConfigThemes.presets[preset].name); + strcat(path, ".ini"); + if (themes_save(path, preset)) { + return true; + } - memcpy(&gGeneral_config, &gGeneral_config_default, sizeof(general_configuration_t)); + return false; +} - if (strcmp(path, "") != 0){ - if (!platform_ensure_directory_exists(path)) { - config_error("Could not create config file (do you have write access to your documents folder?)"); +bool themes_open(const_utf8string path) +{ + FILE *file; + uint8 *lineBuffer; + size_t lineBufferCapacity; + size_t lineLength; + int c, preset; + theme_section_definition *currentSection; + + file = fopen(path, "rb"); + if (file == NULL) + return false; + + // Check if the colour scheme is already loaded + // No nead to read the first two presets as they're hardcoded in + for (preset = 2; preset < gConfigThemes.num_presets; preset++) { + if (strcmp(path, gConfigThemes.presets[preset].name) == 0) { + break; + } + } + // Otherwise allocate one + if (preset == gConfigThemes.num_presets) { + gConfigThemes.num_presets++; + gConfigThemes.presets = realloc(gConfigThemes.presets, sizeof(theme_preset) * gConfigThemes.num_presets); + strcpy(gConfigThemes.presets[preset].name, path_get_filename(path)); + path_remove_extension(gConfigThemes.presets[preset].name); + gConfigThemes.presets[preset].windows = malloc(sizeof(theme_window) * gNumThemeWindows); + gConfigThemes.presets[preset].features.rct1_ride_lights = false; + gConfigThemes.presets[preset].features.rct1_park_lights = false; + gConfigThemes.presets[preset].features.rct1_scenario_font = false; + for (int i = 0; i < (int)gNumThemeWindows; i++) { + gConfigThemes.presets[preset].windows[i] = gThemeWindowDefinitions[i].window; + } + } + + currentSection = NULL; + lineBufferCapacity = 64; + lineBuffer = malloc(lineBufferCapacity); + lineLength = 0; + + // Skim UTF-8 byte order mark + fread(lineBuffer, 3, 1, file); + if (!(lineBuffer[0] == 0xEF && lineBuffer[1] == 0xBB && lineBuffer[2] == 0xBF)) + fseek(file, 0, SEEK_SET); + + while ((c = fgetc(file)) != EOF) { + if (c == '\n' || c == '\r') { + lineBuffer[lineLength++] = 0; + themes_read_properties(&gConfigThemes.presets[preset], ¤tSection, (utf8string)lineBuffer); + lineLength = 0; + } + else { + lineBuffer[lineLength++] = c; + } + + if (lineLength >= lineBufferCapacity) { + lineBufferCapacity *= 2; + lineBuffer = realloc(lineBuffer, lineBufferCapacity); + } + } + + if (lineLength > 0) { + lineBuffer[lineLength++] = 0; + themes_read_properties(&gConfigThemes.presets[preset], ¤tSection, lineBuffer); + } + + free(lineBuffer); + fclose(file); + return true; +} + +static bool themes_save(const_utf8string path, int preset) +{ + FILE *file; + int i, j; + value_union *value; + + file = fopen(path, "wb"); + if (file == NULL) { + log_error("Unable to write to theme file."); + return false; + } + + // Skip the window definition, we'll do that after + for (i = 1; i < countof(_themeSectionDefinitions); i++) { + theme_section_definition *section = &_themeSectionDefinitions[i]; + + fputc('[', file); + fwrite(section->section_name, strlen(section->section_name), 1, file); + fputc(']', file); + fputc('\n', file); + + for (j = 0; j < section->property_definitions_count; j++) { + theme_property_definition *property = §ion->property_definitions[j]; + + fwrite(property->property_name, strlen(property->property_name), 1, file); + fwrite(" = ", 3, 1, file); + + value = (value_union*)((size_t)&gConfigThemes.presets[preset] + (size_t)section->offset + (size_t)property->offset); + + if (property->enum_definitions != NULL) + config_write_enum(file, property->type, value, property->enum_definitions); + else + config_save_property_value(file, property->type, value); + fputc('\n', file); + } + fputc('\n', file); + } + + for (i = 0; i < (int)gNumThemeWindows; i++) { + theme_section_definition *section = &_themeSectionDefinitions[0]; + + fputc('[', file); + fwrite(gThemeWindowDefinitions[i].section_name, strlen(gThemeWindowDefinitions[i].section_name), 1, file); + fputc(']', file); + fputc('\n', file); + + for (j = 0; j < section->property_definitions_count; j++) { + theme_property_definition *property = §ion->property_definitions[j]; + + fwrite(property->property_name, strlen(property->property_name), 1, file); + fwrite(" = ", 3, 1, file); + + value = (value_union*)((size_t)gConfigThemes.presets[preset].windows + (size_t)(sizeof(theme_window) * i) + (size_t)property->offset); + + if (property->enum_definitions != NULL) + config_write_enum(file, property->type, value, property->enum_definitions); + else + config_save_property_value(file, property->type, value); + fputc('\n', file); + } + } + + fclose(file); + return true; +} + + +static void themes_read_properties(theme_preset *theme, theme_section_definition **currentSection, utf8string line) +{ + utf8 *ch = (utf8*)line; + utf8_skip_whitespace(&ch); + + if (*ch == '[') { + const utf8 *sectionName; + int sectionNameSize; + if (config_get_section(ch, §ionName, §ionNameSize)) + *currentSection = themes_get_section_def((utf8string)sectionName, sectionNameSize); + } + else { + if (*currentSection != NULL) { + utf8 *propertyName, *value; + int propertyNameSize, valueSize; + if (config_get_property_name_value(ch, &propertyName, &propertyNameSize, &value, &valueSize)) { + theme_property_definition *property; + property = themes_get_property_def(*currentSection, propertyName, propertyNameSize); + if (property != NULL) + themes_set_property(theme, *currentSection, property, value, valueSize); + } + } + } +} +static void themes_set_property(theme_preset *theme, const theme_section_definition *section, const theme_property_definition *property, utf8string value, int valueSize) +{ + value_union *destValue = (value_union*)((size_t)theme + (size_t)section->offset + (size_t)property->offset); + + // Get getting the address from the windows pointer instead + if (section == &_themeSectionDefinitions[0]) + destValue = (value_union*)((size_t)theme->windows + (size_t)section->offset + (size_t)property->offset); + + if (property->enum_definitions != NULL) + if (config_read_enum(destValue, _configValueTypeSize[property->type], value, valueSize, property->enum_definitions)) return; - } - - sprintf(path, "%s%c%s", path, osinterface_get_path_separator(), "config.ini"); - - fp = fopen(path, "r"); - if (!fp) { - config_create_default(path); - fp = fopen(path, "r"); - if (!fp) - config_error("Could not create config file"); - } - config_parse_settings(fp); - - fclose(fp); + switch (property->type) { + case CONFIG_VALUE_TYPE_BOOLEAN: + if (_strnicmp(value, "false", valueSize) == 0) destValue->value_boolean = false; + else if (_strnicmp(value, "true", valueSize) == 0) destValue->value_boolean = true; + else destValue->value_boolean = strtol(value, NULL, 0) != 0; + break; + case CONFIG_VALUE_TYPE_UINT8: + destValue->value_uint8 = (uint8)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_UINT16: + destValue->value_uint16 = (uint16)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_UINT32: + destValue->value_uint32 = (uint32)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_SINT8: + destValue->value_sint8 = (sint8)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_SINT16: + destValue->value_sint16 = (sint16)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_SINT32: + destValue->value_sint32 = (sint32)strtol(value, NULL, 0); + break; + case CONFIG_VALUE_TYPE_FLOAT: + destValue->value_float = strtof(value, NULL); + break; + case CONFIG_VALUE_TYPE_DOUBLE: + destValue->value_double = strtod(value, NULL); + break; + case CONFIG_VALUE_TYPE_STRING: + SafeFree(destValue->value_string); + destValue->value_string = malloc(valueSize + 1); + memcpy(destValue->value_string, value, valueSize); + destValue->value_string[valueSize] = 0; + break; } - - free(path); - - config_apply_to_old_addresses(); } - -void config_save() -{ - char *configIniPath = osinterface_get_orct2_homefolder();; - - sprintf(configIniPath, "%s%c%s", configIniPath, osinterface_get_path_separator(), "config.ini"); - config_save_ini(configIniPath); - - config_apply_to_old_addresses(); -} - -/** - * Attempts to find the RCT2 installation directory. - * This should be created from some other resource when OpenRCT2 grows. - * @param resultPath Pointer to where the absolute path of the RCT2 installation directory will be copied to. - * @returns 1 if successful, otherwise 0. - */ -static int config_find_rct2_path(char *resultPath) +static theme_section_definition* themes_get_section_def(utf8string name, int size) { int i; - log_verbose("searching common installation locations."); - - const char *searchLocations[] = { - "C:\\Program Files\\Infogrames\\RollerCoaster Tycoon 2", - "C:\\Program Files (x86)\\Infogrames\\RollerCoaster Tycoon 2", - "C:\\Program Files\\Infogrames Interactive\\RollerCoaster Tycoon 2", - "C:\\Program Files (x86)\\Infogrames Interactive\\RollerCoaster Tycoon 2", - "C:\\Program Files\\Atari\\RollerCoaster Tycoon 2", - "C:\\Program Files (x86)\\Atari\\RollerCoaster Tycoon 2", - "C:\\GOG Games\\RollerCoaster Tycoon 2 Triple Thrill Pack" - }; - - for (i = 0; i < countof(searchLocations); i++) { - if (platform_directory_exists(searchLocations[i]) ) { - strcpy(resultPath, searchLocations[i]); - return 1; + // Skip the special definition + for (i = 1; i < countof(_themeSectionDefinitions); i++) { + const_utf8string sectionName = _themeSectionDefinitions[i].section_name; + if (sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0) + return &_themeSectionDefinitions[i]; + } + // Check for window definitions + for (i = 0; i < (int)gNumThemeWindows; i++) { + const_utf8string sectionName = gThemeWindowDefinitions[i].section_name; + if (sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0) { + _themeSectionDefinitions[0].offset = (size_t)(sizeof(theme_window) * i); + return &_themeSectionDefinitions[0]; } } - return 0; -} - -int config_find_or_browse_install_directory() -{ - char *installPath; - - if (!config_find_rct2_path(gGeneral_config.game_path)) { - osinterface_show_messagebox("Unable to find RCT2 installation directory. Please select the directory where you installed RCT2!"); - installPath = osinterface_open_directory_browser("Please select your RCT2 directory"); - if (installPath == NULL) - return 0; - - strcpy(gGeneral_config.game_path, installPath); - } - - config_save(); - return 1; -} - -/** - * Create a new default settings file. - * This should be created from some other resource when openRCT2 grows - * @param path The aboslute path of the config file - */ -static void config_create_default(char *path) -{ - gGeneral_config = gGeneral_config_default; - if (!config_find_or_browse_install_directory()) { - log_fatal("An RCT2 install directory must be specified!"); - exit(-1); - } - - config_save_ini(path); -} - -/** - * Parse settings and set the game veriables - * @param fp file pointer to the settings file - */ -static void config_parse_settings(FILE *fp) -{ - int pos = 0; - char *setting; - char *value; - char *section; - setting = (char *)malloc(MAX_CONFIG_LENGTH); - value = (char *)malloc(MAX_CONFIG_LENGTH); - section = (char*)malloc(MAX_CONFIG_LENGTH); - - while (config_get_line(fp, setting, value) > 0) { - if (strcmp(setting, "section") == 0){ - strcpy(section, value); - continue; + return NULL; } - - if (strcmp(section, "sound") == 0){ - config_sound(setting, value); - } - else if (strcmp(section, "general") == 0){ - config_general(setting, value); - } - - - - } - //RCT2_GLOBAL(0x009AACBC, sint8) = CURRENCY_KRONA; - - - - free(setting); - free(value); - free(section); -} - -static void config_sound(char *setting, char *value){ - if (strcmp(setting, "sound_quality") == 0){ - if (strcmp(value, "low") == 0){ - gSound_config.sound_quality = SOUND_QUALITY_LOW; - } - else if (strcmp(value, "medium") == 0){ - gSound_config.sound_quality = SOUND_QUALITY_MEDIUM; - } - else{ - gSound_config.sound_quality = SOUND_QUALITY_HIGH; - } - } - else if (strcmp(setting, "forced_software_buffering") == 0){ - if (strcmp(value, "true") == 0){ - gSound_config.forced_software_buffering = 1; - } - else{ - gSound_config.forced_software_buffering = 0; - } - } - -} - -static void config_general(char *setting, char *value){ - if (strcmp(setting, "game_path") == 0){ - strcpy(gGeneral_config.game_path, value); - } - else if (strcmp(setting, "screenshot_format") == 0) { - if (strcmp(value, "png") == 0) { - gGeneral_config.screenshot_format = SCREENSHOT_FORMAT_PNG; - } - else if (strcmp(value, "1") == 0) { //TODO: REMOVE LINE AT LATER DATE WHEN EVERYONE HAS NEW CONFIG FORMAT - gGeneral_config.screenshot_format = SCREENSHOT_FORMAT_PNG; - } - else { - gGeneral_config.screenshot_format = SCREENSHOT_FORMAT_BMP; - } - } - else if (strcmp(setting, "play_intro") == 0) { - gGeneral_config.play_intro = (strcmp(value, "true") == 0); - } - else if (strcmp(setting, "confirmation_prompt") == 0) { - gGeneral_config.confirmation_prompt = (strcmp(value, "true") == 0); - } - else if (strcmp(setting, "edge_scrolling") == 0){ - if (strcmp(value, "true") == 0){ - gGeneral_config.edge_scrolling = 1; - } - else { - gGeneral_config.edge_scrolling = 0; - } - } - else if (strcmp(setting, "measurement_format") == 0){ - if (strcmp(value, "imperial") == 0){ - gGeneral_config.measurement_format = MEASUREMENT_FORMAT_IMPERIAL; - } - else{ - gGeneral_config.measurement_format = MEASUREMENT_FORMAT_METRIC; - } - } - else if (strcmp(setting, "temperature_format") == 0){ - if (strcmp(value, "fahrenheit") == 0){ - gGeneral_config.temperature_format = TEMPERATURE_FORMAT_F; - } - else{ - gGeneral_config.temperature_format = TEMPERATURE_FORMAT_C; - } - } - else if (strcmp(setting, "currency") == 0){ - config_parse_currency(value); - } - else if (strcmp(setting, "always_show_gridlines") == 0){ - if (strcmp(value, "true") == 0){ - gGeneral_config.always_show_gridlines = 1; - } - else { - gGeneral_config.always_show_gridlines = 0; - } - } - else if (strcmp(setting, "landscape_smoothing") == 0){ - if (strcmp(value, "true") == 0){ - gGeneral_config.landscape_smoothing = 1; - } - else { - gGeneral_config.landscape_smoothing = 0; - } - } - else if (strcmp(setting, "show_height_as_units") == 0){ - if (strcmp(value, "true") == 0){ - gGeneral_config.show_height_as_units = 1; - } - else { - gGeneral_config.show_height_as_units = 0; - } - } - else if (strcmp(setting, "save_plugin_data") == 0){ - if (strcmp(value, "true") == 0){ - gGeneral_config.save_plugin_data = 1; - } - else { - gGeneral_config.save_plugin_data = 0; - } - } - else if (strcmp(setting, "fullscreen_mode") == 0){ - if (strcmp(value, "window") == 0){ - gGeneral_config.fullscreen_mode = 0; - } - else if (strcmp(value, "fullscreen") == 0){ - gGeneral_config.fullscreen_mode = 1; - } - else - gGeneral_config.fullscreen_mode = 2; - } - else if (strcmp(setting, "window_width") == 0) { - gGeneral_config.window_width = atoi(value); - } - else if (strcmp(setting, "window_height") == 0) { - gGeneral_config.window_height = atoi(value); - } - else if (strcmp(setting, "language") == 0) { - gGeneral_config.language = atoi(value); - } - else if (strcmp(setting, "window_snap_proximity") == 0) { - gGeneral_config.window_snap_proximity = clamp(0, atoi(value), 255); - } -} - -/** - * Read one line in the settings file - * @param fp filepointer to the config file - * @param setting pointer where to to store the setting - * @param value pointer to where to store the value - * @return < 0 if EOF file is reached or other error - */ -static int config_get_line(FILE *fp, char *setting, char *value) -{ - int c; - - c = fgetc(fp); - while (isspace(c)){ - c = getc(fp); - } - - if (c == '['){ - return config_parse_section(fp, setting, value); - } - else if(c == '#'){ - while (c != '\n'){ - c = fgetc(fp); - } - return 1; - } - if (c == EOF){ - return -1; - } - - while (!isalpha(c)){ - c = fgetc(fp); - } - - //if the first char is not the '[' char, it belongs to the setting name. We want to leave that for the next fn - fseek(fp, -1, SEEK_CUR); - - config_parse_setting(fp, setting); - - c = fgetc(fp); - while (isspace(c)){ - c = getc(fp); - } - - if (c != '='){ - config_error("There is an error in your configuration file"); - return -1; - } - - config_parse_value(fp, value); - return 1; - - -} - -/** -* Parse the value of a setting -* @param fp a filepointer to the config file -* @param value a pointer to where to store the setting -* @return < 0 if EOF is reached -*/ -static int config_parse_setting(FILE *fp, char *setting){ - long start, end; - int size, c, pos = 0; - - - start = ftell(fp); - c = fgetc(fp); - - while (isspace(c)){ - start = ftell(fp); - c = fgetc(fp); - - } - if (c == EOF){ - return -1; - } - - while (isalpha(c) || c == '_'){ - c = fgetc(fp); - } - - end = ftell(fp); - size = end - start; - - - fseek(fp, start, SEEK_SET); - c = fgetc(fp); - while (isalpha(c) || c == '_'){ - setting[pos] = (char)c; - c = fgetc(fp); - pos++; - } - setting[pos] = '\0'; - return 1; -} - -/** - * Parse the value of a setting - * @param fp a filepointer to the config file - * @param value a pointer to where to store the value - * @return < 0 if EOF is reached - */ -static int config_parse_value(FILE *fp, char *value) -{ - long start, end; - int size, c, pos = 0; - - start = ftell(fp); - c = fgetc(fp); - while (isspace(c)) { - start = ftell(fp); - c = fgetc(fp); - } - - while (c != EOF && c != '\n') { - c = fgetc(fp); - } - - end = ftell(fp); - size = end - start; - if (size > MAX_CONFIG_LENGTH) - config_error("One of your settings is too long"); - - fseek(fp, start, SEEK_SET); - c = fgetc(fp); - while (c != EOF && c != '\n') { - value[pos] = (char)tolower(c); - c = fgetc(fp); - pos++; - } - value[pos] = '\0'; - return 0; -} - -/** - * Parse the current section - * @param fp Filepointer to the config file - * @param setting This is set to contain the string "section" - * @param value Pointer to where the section name should be put - * @return < 0 if EOF is reached - */ -static int config_parse_section(FILE *fp, char *setting, char *value){ - int size, c, pos = 0; - long start, end; - - strcpy(setting, "section\0"); - c = fgetc(fp); - start = ftell(fp); - while (c != ']' && c != EOF){ - c = fgetc(fp); - } - end = ftell(fp); - size = end - start; - fseek(fp, start - 1, SEEK_SET); - c = fgetc(fp); - while (c != ']' && c != EOF){ - value[pos] = (char)c; - c = fgetc(fp); - pos++; - } - - value[pos] = '\0'; - if (c != ']'){ - config_error("There is an error with the section headers"); - } - c = fgetc(fp); //devour ']' - - return 1; -} - -static int config_parse_currency(char *currency) +static theme_property_definition *themes_get_property_def(theme_section_definition *section, utf8string name, int size) { int i; - for (i = 0; i < countof(_currencyLookupTable); i++) { - if (_strcmpi(currency, _currencyLookupTable[i].key) == 0) { - gGeneral_config.currency_format = _currencyLookupTable[i].value; - return 1; - } + + for (i = 0; i < section->property_definitions_count; i++) { + const_utf8string propertyName = section->property_definitions[i].property_name; + if (propertyName[size] == 0 && _strnicmp(propertyName, name, size) == 0) + return §ion->property_definitions[i]; } - config_error("Invalid currency set in config file"); - return -1; -} -/** - * Error with config file. Print error message an quit the game - * @param msg Message to print in message box - */ -static void config_error(char *msg){ - - osinterface_show_messagebox(msg); - //TODO:SHUT DOWN EVERYTHING! - + return NULL; } -#pragma region Obsolete - -// The following functions are related to the original configuration file. This has now been replaced with a new configuration -// INI file located in the user's OpenRCT2 home directory. - -/** - * Reads the config file data/config.cfg - * rct2: 0x006752D5 - */ -void config_dat_load() -{ - FILE *fp=NULL; - - const char *path = get_file_path(PATH_ID_GAMECFG); - - fp = fopen(path, "rb"); - - if (fp != NULL) { - // Read and check magic number - fread(RCT2_ADDRESS(0x013CE928, void), 1, 4, fp); - - if (RCT2_GLOBAL(0x013CE928, int) == MagicNumber) { - // Read options - fread((void*)0x009AAC5C, 1, 2155, fp); - fclose(fp); - - //general configuration - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, sint8) = gGeneral_config.edge_scrolling; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, sint8) = gGeneral_config.currency_format; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) = gGeneral_config.measurement_format; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, sint8) = gGeneral_config.temperature_format; - - // always show gridlines - if (gGeneral_config.always_show_gridlines){ - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES; - } - else { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES; - } - - // landscape smoothing - if (!gGeneral_config.landscape_smoothing){ - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE; - } - else { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE; - } - - // show height as units - if (gGeneral_config.show_height_as_units){ - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; - } - else { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; - } - - // save plugin data - if (gGeneral_config.save_plugin_data){ - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_SAVE_PLUGIN_DATA; - } - else { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= !CONFIG_FLAG_SAVE_PLUGIN_DATA; - } - - //sound configuration - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = gSound_config.sound_quality; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, sint8) = gSound_config.forced_software_buffering; - - // Line below is temporaraly disabled until all config is in the new format. - //if (RCT2_GLOBAL(0x009AB4C6, sint8) == 1) - // return; - - - RCT2_GLOBAL(0x009AB4C6, sint8) = 1; // no idea on what this does - - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 2) * 256; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 1) * 256; - RCT2_GLOBAL(0x009AA00D, sint8) = 0; - } - - } - - /* TODO: CLEANUP - - if (RCT2_GLOBAL(0x009AB4C6, sint8) == 1) - return; - RCT2_GLOBAL(0x009AB4C6, sint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, sint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, sint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = 0; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 1) * 256; - RCT2_GLOBAL(0x009AA00D, sint8) = 1; - } - - } - - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_MEM_TOTAL_PHYSICAL, uint32) > 0x4000000) { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 1; - if (RCT2_GLOBAL(RCT2_ADDRESS_MEM_TOTAL_PHYSICAL, uint32) > 0x8000000) - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8) = 2; - } - */ - - - RCT2_GLOBAL(0x009AAC75, sint8) = RCT2_ADDRESS(0x009AF601, sint8)[RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8)]; - RCT2_GLOBAL(0x009AAC76, sint8) = RCT2_ADDRESS(0x009AF604, sint8)[RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, sint8)]; - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = 0; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, sint16) = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, sint8) + 1) * 256; - RCT2_GLOBAL(0x009AA00D, sint8) = 1; -} - -/** - * Save configuration to the data/config.cfg file - * rct2: 0x00675487 - */ -void config_dat_save() -{ - FILE *fp = fopen(get_file_path(PATH_ID_GAMECFG), "wb"); - if (fp != NULL){ - fwrite(&MagicNumber, 4, 1, fp); - fwrite((void*)0x009AAC5C, 2155, 1, fp); - fclose(fp); - } -} - -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/config.h b/src/config.h index 3098031780..d9fcd3ae62 100644 --- a/src/config.h +++ b/src/config.h @@ -89,37 +89,34 @@ enum { MEASUREMENT_FORMAT_METRIC }; -enum{ - SOUND_QUALITY_LOW, - SOUND_QUALITY_MEDIUM, - SOUND_QUALITY_HIGH - +enum { + AUTOSAVE_EVERY_WEEK, + AUTOSAVE_EVERY_2_WEEKS, + AUTOSAVE_EVERY_MONTH, + AUTOSAVE_EVERY_4_MONTHS, + AUTOSAVE_EVERY_YEAR, + AUTOSAVE_NEVER }; -extern uint16 gShortcutKeys[SHORTCUT_COUNT]; +enum { + DATE_FORMAT_DMY, + DATE_FORMAT_MDY +}; -void config_reset_shortcut_keys(); -void config_load(); -void config_save(); -int config_find_or_browse_install_directory(); +enum { + TITLE_SEQUENCE_RCT1, + TITLE_SEQUENCE_RCT1_AA, + TITLE_SEQUENCE_RCT1_AA_LL, + TITLE_SEQUENCE_RCT2, + TITLE_SEQUENCE_OPENRCT2, + TITLE_SEQUENCE_RANDOM +}; - -// New config format -#define MAX_CONFIG_LENGTH 256 - -typedef struct sound_configuration { - - sint8 sound_quality; - sint8 forced_software_buffering; -} sound_configuration_t; - - - -typedef struct general_configuration { +typedef struct { uint8 play_intro; uint8 confirmation_prompt; uint8 screenshot_format; - char game_path[MAX_PATH]; + utf8string game_path; sint8 measurement_format; sint8 temperature_format; sint8 currency_format; @@ -129,44 +126,117 @@ typedef struct general_configuration { sint8 landscape_smoothing; sint8 show_height_as_units; sint8 save_plugin_data; + uint8 debugging_tools; //new uint8 fullscreen_mode; - sint16 window_width; - sint16 window_height; + sint32 fullscreen_width; + sint32 fullscreen_height; + sint32 window_width; + sint32 window_height; uint16 language; uint8 window_snap_proximity; -} general_configuration_t; + uint8 autosave_frequency; + uint8 hardware_display; + uint8 test_unfinished_tracks; + uint8 no_test_crashes; + uint8 date_format; + uint8 auto_staff_placement; + utf8string last_run_version; + uint8 title_sequence; +} general_configuration; -static const struct { const char *key; int value; } _currencyLookupTable[] = { - { "GBP", CURRENCY_POUNDS }, - { "USD", CURRENCY_DOLLARS }, - { "FRF", CURRENCY_FRANC }, - { "DEM", CURRENCY_DEUTSCHMARK }, - { "YEN", CURRENCY_YEN }, - { "ESP", CURRENCY_PESETA }, - { "ITL", CURRENCY_LIRA }, - { "NLG", CURRENCY_GUILDERS }, - { "NOK", CURRENCY_KRONA }, - { "SEK", CURRENCY_KRONA }, - { "DEK", CURRENCY_KRONA }, - { "EUR", CURRENCY_EUROS }, +typedef struct { + uint8 toolbar_show_finances; + uint8 toolbar_show_research; + uint8 toolbar_show_cheats; + uint8 allow_subtype_switching; + uint8 console_small_font; + utf8string current_theme_preset; +} interface_configuration; - { "\xA3", CURRENCY_POUNDS }, - { "\x24", CURRENCY_DOLLARS }, - { "\xA5", CURRENCY_YEN }, - { "\xB5", CURRENCY_EUROS } -}; +typedef struct { + uint8 title_music; + uint8 sound; + uint8 ride_music; + uint8 master_volume; + uint8 music_volume; +} sound_configuration; -typedef struct shortcut_entry{ +typedef struct { + uint8 fast_lift_hill; + uint8 disable_brakes_failure; + uint8 disable_all_breakdowns; + uint8 unlock_all_prices; + uint8 build_in_pause_mode; +} cheat_configuration; + +typedef struct { + utf8string channel; + uint8 enable_follower_peep_names; + uint8 enable_follower_peep_tracking; + uint8 enable_chat_peep_names; + uint8 enable_chat_peep_tracking; + uint8 enable_news; +} twitch_configuration; + +typedef struct theme_window { + uint8 colours[6]; + + // Define any other settings for all windows here + +} theme_window; + +// Define structures for any other settings here +typedef struct { + uint8 rct1_ride_lights; + uint8 rct1_park_lights; + uint8 rct1_scenario_font; +} theme_features; + + +typedef struct theme_preset { + char name[256]; + theme_window *windows; + + // Add structures for any other settings here + theme_features features; + +} theme_preset; + +typedef struct { + theme_preset *presets; + uint16 num_presets; +} themes_configuration; + +typedef struct { uint8 key; uint8 modifier; -}shortcut_entry; +} shortcut_entry; -//typedef struct hotkey_configuration{ +extern general_configuration gConfigGeneral; +extern interface_configuration gConfigInterface; +extern sound_configuration gConfigSound; +extern cheat_configuration gConfigCheat; +extern twitch_configuration gConfigTwitch; +extern themes_configuration gConfigThemes; -//}; -extern general_configuration_t gGeneral_config; -extern sound_configuration_t gSound_config; +extern uint16 gShortcutKeys[SHORTCUT_COUNT]; + +void config_set_defaults(); +bool config_open_default(); +bool config_save_default(); + +uint16 getLanguage(); + +void config_reset_shortcut_keys(); +bool config_shortcut_keys_load(); +bool config_shortcut_keys_save(); + +bool config_find_or_browse_install_directory(); + +void themes_set_default(); +void themes_load_presets(); +bool themes_save_preset(int preset); #endif diff --git a/src/cursors.c b/src/cursors.c new file mode 100644 index 0000000000..720f40833a --- /dev/null +++ b/src/cursors.c @@ -0,0 +1,533 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Duncan Frost +* 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 "cursors.h" + +unsigned char blank_cursor_data[32 * 4] = { + 0 +}; +unsigned char blank_cursor_mask[32 * 4] = { + 0 +}; + +unsigned char up_arrow_cursor_data[32 * 4] = { + 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, + 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x02, 0x20, 0x00, + 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +unsigned char up_arrow_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00, + 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +unsigned char up_down_arrow_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0xA0, 0x00, + 0x00, 0x05, 0x50, 0x00, 0x00, 0x0A, 0x28, 0x00, 0x00, 0x17, 0x74, 0x00, 0x00, 0x21, 0x42, 0x00, + 0x00, 0x1D, 0xDC, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00, + 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0xD0, 0x00, 0x00, 0x1D, 0x5C, 0x00, + 0x00, 0x21, 0x42, 0x00, 0x00, 0x17, 0x74, 0x00, 0x00, 0x0A, 0x28, 0x00, 0x00, 0x05, 0x50, 0x00, + 0x00, 0x02, 0xA0, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +unsigned char up_down_arrow_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x3F, 0x7E, 0x00, + 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x1F, 0x7C, 0x00, + 0x00, 0x3F, 0x7E, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x07, 0x70, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +unsigned char zzz_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, + 0x00, 0x00, 0x03, 0xE2, 0x00, 0x00, 0xFC, 0x34, 0x00, 0x01, 0x07, 0x62, 0x00, 0x3F, 0xEA, 0xDC, + 0x00, 0x40, 0xD4, 0x20, 0x00, 0x3D, 0xBB, 0xC0, 0x3F, 0xCB, 0x04, 0x00, 0x40, 0x34, 0xF8, 0x00, + 0x40, 0x2F, 0x00, 0x00, 0x3C, 0x40, 0x80, 0x00, 0x08, 0xBF, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x23, 0xC0, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +unsigned char zzz_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, + 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFB, 0xDC, + 0x00, 0x7F, 0xF7, 0xE0, 0x00, 0x3F, 0xFB, 0xC0, 0x3F, 0xCF, 0xFC, 0x00, 0x7F, 0xFC, 0xF8, 0x00, + 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x0F, 0xBF, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0x3F, 0xC0, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +unsigned char diagonal_arrow_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +unsigned char diagonal_arrow_cursor_mask[32 * 4] = { + 0xFE, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, + 0x01, 0xC2, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +unsigned char picker_cursor_data[32 * 4] = { + 0x00, 0x07, 0xC0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x13, 0x30, 0x00, 0x00, 0x17, 0xB0, 0x00, + 0x00, 0x17, 0xB0, 0x00, 0x00, 0x13, 0x30, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x17, 0x30, 0x00, 0x00, 0x12, 0x30, 0x00, 0x00, 0x21, 0x18, 0x00, + 0x00, 0x23, 0x18, 0x00, 0x00, 0x44, 0x8C, 0x00, 0x00, 0x44, 0x8C, 0x00, 0x00, 0x88, 0x46, 0x00, + 0x00, 0x90, 0x26, 0x00, 0x01, 0x10, 0x23, 0x00, 0x01, 0x20, 0x13, 0x00, 0x02, 0x40, 0x09, 0x80, + 0x02, 0x40, 0x09, 0x80, 0x04, 0x80, 0x04, 0xC0, 0x04, 0x80, 0x04, 0xC0, 0x04, 0x80, 0x04, 0xC0, + 0x04, 0x80, 0x04, 0xC0, 0x04, 0x80, 0x04, 0xC0, 0x04, 0x40, 0x08, 0xC0, 0x02, 0x40, 0x09, 0x80, + 0x01, 0x20, 0x13, 0x00, 0x00, 0x90, 0x26, 0x00, 0x00, 0x68, 0x5C, 0x00, 0x00, 0x1C, 0xF0, 0x00, +}; +unsigned char picker_cursor_mask[32 * 4] = { + 0x00, 0x07, 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, + 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xF8, 0x00, + 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x7C, 0xFC, 0x00, 0x00, 0x7C, 0xFC, 0x00, 0x00, 0xF8, 0x7E, 0x00, + 0x00, 0xF0, 0x3E, 0x00, 0x01, 0xF0, 0x3F, 0x00, 0x01, 0xE0, 0x1F, 0x00, 0x03, 0xC0, 0x0F, 0x80, + 0x03, 0xC0, 0x0F, 0x80, 0x07, 0x80, 0x07, 0xC0, 0x07, 0x80, 0x07, 0xC0, 0x07, 0x80, 0x07, 0xC0, + 0x07, 0x80, 0x07, 0xC0, 0x07, 0x80, 0x07, 0xC0, 0x07, 0xC0, 0x0F, 0xC0, 0x03, 0xC0, 0x0F, 0x80, + 0x01, 0xE0, 0x1F, 0x00, 0x00, 0xF0, 0x3E, 0x00, 0x00, 0x78, 0x7C, 0x00, 0x00, 0x1C, 0xF0, 0x00, +}; + +unsigned char tree_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0x89, 0xC0, 0x00, 0x02, 0x06, 0x20, + 0x00, 0x07, 0x00, 0x18, 0x00, 0x07, 0x40, 0x04, 0x00, 0x03, 0x80, 0x04, 0x00, 0x01, 0xC0, 0x02, + 0x00, 0x03, 0x82, 0x02, 0x00, 0x03, 0xD0, 0x04, 0x00, 0x07, 0xF9, 0x08, 0x00, 0x0F, 0x6E, 0x04, + 0x00, 0x0E, 0xB8, 0x82, 0x00, 0x0F, 0x44, 0x22, 0x00, 0x0F, 0xA8, 0x46, 0x00, 0x0F, 0xFC, 0x16, + 0x00, 0x07, 0xEE, 0x8C, 0x0F, 0x81, 0xFF, 0xD8, 0x08, 0x80, 0x7D, 0xF0, 0x08, 0x80, 0x3A, 0x00, + 0x08, 0x80, 0x1A, 0x00, 0x08, 0x80, 0x1A, 0x00, 0x08, 0x80, 0x12, 0x00, 0x08, 0x80, 0x12, 0x00, + 0x08, 0x80, 0x11, 0x00, 0xF8, 0xF8, 0x60, 0x80, 0x40, 0x11, 0x80, 0x60, 0x20, 0x22, 0x09, 0x90, + 0x10, 0x41, 0xD5, 0x60, 0x08, 0x80, 0x22, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char tree_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xF9, 0xC0, 0x00, 0x03, 0xFF, 0xE0, + 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFE, + 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFC, + 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, + 0x00, 0x07, 0xFF, 0xFC, 0x0F, 0x81, 0xFF, 0xF8, 0x0F, 0x80, 0x7F, 0xF0, 0x0F, 0x80, 0x3E, 0x00, + 0x0F, 0x80, 0x1E, 0x00, 0x0F, 0x80, 0x1E, 0x00, 0x0F, 0x80, 0x1E, 0x00, 0x0F, 0x80, 0x1E, 0x00, + 0x0F, 0x80, 0x1F, 0x00, 0xFF, 0xF8, 0x7F, 0x80, 0x7F, 0xF1, 0xFF, 0xE0, 0x3F, 0xE3, 0xFF, 0xF0, + 0x1F, 0xC1, 0xF7, 0x60, 0x0F, 0x80, 0x22, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char fountain_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x7B, 0xC0, 0x00, 0x01, 0x8B, 0x30, 0x00, 0x02, 0x17, 0xC8, + 0x00, 0x02, 0x0F, 0x88, 0x0F, 0x83, 0x80, 0x38, 0x08, 0x82, 0x7F, 0xD8, 0x08, 0x81, 0x01, 0xF0, + 0x08, 0x80, 0xE3, 0xE0, 0x08, 0x80, 0x3F, 0x80, 0x08, 0x80, 0x17, 0x00, 0x08, 0x80, 0x13, 0x00, + 0x08, 0x80, 0x13, 0x00, 0xF8, 0xF8, 0x27, 0x80, 0x40, 0x10, 0x4E, 0xC0, 0x20, 0x20, 0x80, 0xE0, + 0x10, 0x40, 0xC1, 0xA0, 0x08, 0x80, 0x7F, 0xC0, 0x05, 0x00, 0x1F, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char fountain_down_cursor_mask[32 * 4] = { + 0x00, 0x01, 0x04, 0x00, 0x00, 0x10, 0x10, 0x81, 0x00, 0x00, 0x41, 0x14, 0x00, 0x05, 0x08, 0x20, + 0x00, 0x00, 0x22, 0x81, 0x00, 0x00, 0x88, 0x10, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xF8, + 0x00, 0x03, 0xFF, 0xF8, 0x0F, 0x83, 0xFF, 0xF8, 0x0F, 0x83, 0xFF, 0xF8, 0x0F, 0x81, 0xFF, 0xF0, + 0x0F, 0x80, 0xFF, 0xE0, 0x0F, 0x80, 0x3F, 0x80, 0x0F, 0x80, 0x1F, 0x00, 0x0F, 0x80, 0x1F, 0x00, + 0x0F, 0x80, 0x1F, 0x00, 0xFF, 0xF8, 0x3F, 0x80, 0x7F, 0xF0, 0x7F, 0xC0, 0x3F, 0xE0, 0xFF, 0xE0, + 0x1F, 0xC0, 0xFF, 0xE0, 0x0F, 0x80, 0x7F, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char statue_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x07, 0x03, 0x30, + 0x00, 0x02, 0x84, 0x98, 0x00, 0x01, 0x44, 0x98, 0x00, 0x00, 0xB5, 0xA8, 0x00, 0x00, 0x4A, 0xD0, + 0x00, 0x00, 0x21, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x10, 0x80, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x0F, 0x80, 0x08, 0x80, 0x08, 0x80, 0x04, 0x80, 0x08, 0x80, 0x05, 0x00, + 0x08, 0x80, 0x0D, 0x00, 0x08, 0x80, 0x09, 0x00, 0x08, 0x80, 0x3F, 0x80, 0x08, 0x80, 0x20, 0x80, + 0x08, 0x80, 0x20, 0x80, 0xF8, 0xF8, 0x20, 0x80, 0x40, 0x10, 0x20, 0x80, 0x20, 0x20, 0x20, 0x80, + 0x10, 0x40, 0x7F, 0xC0, 0x08, 0x80, 0x80, 0x20, 0x05, 0x00, 0xFF, 0xE0, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char statue_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x07, 0x03, 0x30, + 0x00, 0x03, 0x87, 0x98, 0x00, 0x01, 0xC7, 0x98, 0x00, 0x00, 0xF7, 0xB8, 0x00, 0x00, 0x7E, 0xF0, + 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x1F, 0x80, + 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x07, 0x80, 0x0F, 0x80, 0x07, 0x00, + 0x0F, 0x80, 0x0F, 0x00, 0x0F, 0x80, 0x0F, 0x00, 0x0F, 0x80, 0x3F, 0x80, 0x0F, 0x80, 0x3F, 0x80, + 0x0F, 0x80, 0x3F, 0x80, 0xFF, 0xF8, 0x3F, 0x80, 0x7F, 0xF0, 0x3F, 0x80, 0x3F, 0xE0, 0x3F, 0x80, + 0x1F, 0xC0, 0x7F, 0xC0, 0x0F, 0x80, 0xFF, 0xE0, 0x07, 0x00, 0xFF, 0xE0, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char bench_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x80, 0x00, + 0x00, 0x04, 0x60, 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x05, 0x81, 0x80, + 0x00, 0x05, 0x60, 0x60, 0x00, 0x0D, 0x18, 0x18, 0x00, 0x33, 0x06, 0x04, 0x00, 0xC0, 0xC1, 0x84, + 0x00, 0xF0, 0x30, 0x64, 0x00, 0xAC, 0x0C, 0x1C, 0x00, 0xA7, 0x03, 0x14, 0x00, 0x40, 0xC0, 0xD4, + 0x00, 0x00, 0xF0, 0x34, 0x0F, 0x80, 0xAC, 0x0C, 0x08, 0x80, 0xA3, 0x3C, 0x08, 0x80, 0x41, 0xD4, + 0x08, 0x80, 0x01, 0xD4, 0x08, 0x80, 0x01, 0x48, 0x08, 0x80, 0x01, 0x40, 0x08, 0x80, 0x00, 0x80, + 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char bench_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0xE0, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0x80, + 0x00, 0x07, 0x7F, 0xE0, 0x00, 0x0F, 0x1F, 0xF8, 0x00, 0x3F, 0x07, 0xFC, 0x00, 0xFF, 0xC1, 0xFC, + 0x00, 0xFF, 0xF0, 0x7C, 0x00, 0xEF, 0xFC, 0x1C, 0x00, 0xE7, 0xFF, 0x1C, 0x00, 0x40, 0xFF, 0xDC, + 0x00, 0x00, 0xFF, 0xFC, 0x0F, 0x80, 0xEF, 0xFC, 0x0F, 0x80, 0xE3, 0xFC, 0x0F, 0x80, 0x41, 0xDC, + 0x0F, 0x80, 0x01, 0xDC, 0x0F, 0x80, 0x01, 0xC8, 0x0F, 0x80, 0x01, 0xC0, 0x0F, 0x80, 0x00, 0x80, + 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char cross_hair_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE2, 0x3F, 0x80, + 0x10, 0x15, 0x40, 0x40, 0x0F, 0xE2, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +unsigned char cross_hair_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE2, 0x3F, 0x80, + 0x1F, 0xF7, 0x7F, 0xC0, 0x0F, 0xE2, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +unsigned char bin_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xC3, 0x80, 0x00, 0x01, 0x00, 0xC0, 0x00, 0x02, 0x57, 0xE0, + 0x00, 0x02, 0x00, 0x60, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x01, 0x01, 0xC0, 0x00, 0x01, 0x40, 0xC0, + 0x00, 0x01, 0x50, 0xC0, 0x0F, 0x81, 0x50, 0x40, 0x08, 0x81, 0x51, 0x40, 0x08, 0x81, 0x51, 0x40, + 0x08, 0x81, 0x55, 0x40, 0x08, 0x81, 0x55, 0x40, 0x08, 0x81, 0x55, 0x40, 0x08, 0x81, 0x55, 0x40, + 0x08, 0x81, 0x55, 0x40, 0xF8, 0xF9, 0x55, 0x40, 0x40, 0x11, 0x55, 0x40, 0x20, 0x21, 0xFF, 0xC0, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char bin_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xE0, + 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xC0, + 0x00, 0x01, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, + 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, + 0x0F, 0x81, 0xFF, 0xC0, 0xFF, 0xF9, 0xFF, 0xC0, 0x7F, 0xF1, 0xFF, 0xC0, 0x3F, 0xE1, 0xFF, 0xC0, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char lamppost_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xFF, 0x80, + 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x32, 0x00, + 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x94, 0x80, + 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x00, 0x94, 0x80, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x0F, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, + 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x1C, 0x00, + 0x08, 0x80, 0x1C, 0x00, 0xF8, 0xF8, 0x32, 0x00, 0x40, 0x10, 0x61, 0x00, 0x20, 0x20, 0x61, 0x00, + 0x10, 0x40, 0x71, 0x00, 0x08, 0x80, 0x7D, 0x00, 0x05, 0x00, 0xFF, 0x80, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char lamppost_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0x80, + 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x9C, 0x80, + 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x00, 0x9C, 0x80, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x00, + 0x00, 0x00, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, + 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, + 0x0F, 0x80, 0x1C, 0x00, 0xFF, 0xF8, 0x3E, 0x00, 0x7F, 0xF0, 0x7F, 0x00, 0x3F, 0xE0, 0x7F, 0x00, + 0x1F, 0xC0, 0x7F, 0x00, 0x0F, 0x80, 0x7F, 0x00, 0x07, 0x00, 0xFF, 0x80, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char fence_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x4E, 0x60, 0x00, 0x00, + 0x43, 0xB0, 0x00, 0x00, 0x20, 0xB1, 0x80, 0x00, 0x2C, 0x3A, 0xC0, 0x00, 0x2F, 0x0E, 0xC6, 0x00, + 0x2C, 0x82, 0xCB, 0x00, 0x2C, 0xB0, 0x6B, 0x18, 0x6C, 0xBC, 0x1B, 0x2C, 0x7C, 0xB2, 0x83, 0x2C, + 0x1E, 0xB2, 0xE1, 0xAC, 0x07, 0xB2, 0xD8, 0x6C, 0x01, 0xF2, 0xCA, 0x0C, 0x00, 0x7A, 0xCB, 0x86, + 0x00, 0x1E, 0xCB, 0x66, 0x0F, 0x87, 0xCB, 0x2E, 0x08, 0x81, 0xEB, 0x2C, 0x08, 0x80, 0x7B, 0x2C, + 0x08, 0x80, 0x1F, 0x2C, 0x08, 0x80, 0x07, 0xAC, 0x08, 0x80, 0x01, 0xEC, 0x08, 0x80, 0x00, 0x78, + 0x08, 0x80, 0x00, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char fence_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x7E, 0x60, 0x00, 0x00, + 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xF1, 0x80, 0x00, 0x3F, 0xFB, 0xC0, 0x00, 0x3F, 0xFF, 0xC6, 0x00, + 0x3C, 0xFF, 0xCF, 0x00, 0x3C, 0xFF, 0xEF, 0x18, 0x7C, 0xFF, 0xFF, 0x3C, 0x7C, 0xF3, 0xFF, 0x3C, + 0x1E, 0xF3, 0xFF, 0xBC, 0x07, 0xF3, 0xDF, 0xFC, 0x01, 0xF3, 0xCF, 0xFC, 0x00, 0x7B, 0xCF, 0xFE, + 0x00, 0x1F, 0xCF, 0x7E, 0x0F, 0x87, 0xCF, 0x3E, 0x0F, 0x81, 0xEF, 0x3C, 0x0F, 0x80, 0x7F, 0x3C, + 0x0F, 0x80, 0x1F, 0x3C, 0x0F, 0x80, 0x07, 0xBC, 0x0F, 0x80, 0x01, 0xFC, 0x0F, 0x80, 0x00, 0x78, + 0x0F, 0x80, 0x00, 0x18, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char flower_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x18, 0x44, 0x30, + 0x00, 0x24, 0x54, 0x48, 0x00, 0x22, 0x54, 0x88, 0x00, 0x11, 0x55, 0x10, 0x00, 0x0A, 0xBA, 0xA0, + 0x00, 0x05, 0xBB, 0x40, 0x00, 0x03, 0xC7, 0x80, 0x00, 0x7C, 0x92, 0x7C, 0x00, 0x83, 0x47, 0x82, + 0x01, 0x1D, 0x89, 0xF1, 0x00, 0x83, 0x23, 0x82, 0x00, 0x7C, 0x8A, 0x7C, 0x00, 0x03, 0xE7, 0x80, + 0x00, 0x05, 0xBB, 0x40, 0x0F, 0x8A, 0xBA, 0xA0, 0x08, 0x91, 0x55, 0x10, 0x08, 0x92, 0x54, 0x90, + 0x08, 0x8C, 0x44, 0x6C, 0x08, 0x98, 0x44, 0x32, 0x08, 0xA6, 0x44, 0x42, 0x08, 0xA1, 0x28, 0x82, + 0x08, 0xA0, 0xB9, 0x24, 0xF8, 0xFA, 0xBA, 0x44, 0x40, 0x11, 0x6A, 0x88, 0x20, 0x28, 0xED, 0x10, + 0x10, 0x46, 0x4A, 0x60, 0x08, 0x81, 0x81, 0x80, 0x05, 0x00, 0x7E, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char flower_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x18, 0x7C, 0x30, + 0x00, 0x3C, 0x7C, 0x78, 0x00, 0x3E, 0x7C, 0xF8, 0x00, 0x1F, 0x7D, 0xF0, 0x00, 0x0F, 0xBB, 0xE0, + 0x00, 0x07, 0xBB, 0xC0, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x7C, 0xFE, 0x7C, 0x00, 0xFF, 0xFF, 0xFE, + 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x7C, 0xFE, 0x7C, 0x00, 0x03, 0xFF, 0x80, + 0x00, 0x07, 0xBB, 0xC0, 0x0F, 0x8F, 0xBB, 0xE0, 0x0F, 0x9F, 0x7D, 0xF0, 0x0F, 0x9E, 0x7C, 0xF0, + 0x0F, 0x8C, 0x7C, 0x6C, 0x0F, 0x98, 0x7C, 0x3E, 0x0F, 0xBE, 0x7C, 0x7E, 0x0F, 0xBF, 0x38, 0xFE, + 0x0F, 0xBF, 0xB9, 0xFC, 0xFF, 0xFF, 0xBB, 0xFC, 0x7F, 0xFF, 0xFB, 0xF8, 0x3F, 0xEF, 0xFF, 0xF0, + 0x1F, 0xC7, 0xFF, 0xE0, 0x0F, 0x81, 0xFF, 0x80, 0x07, 0x00, 0x7E, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char path_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x01, 0x85, 0x80, 0x00, + 0x06, 0x48, 0x60, 0x00, 0x1A, 0x24, 0x58, 0x00, 0x62, 0x3A, 0x46, 0x00, 0x79, 0xC1, 0x45, 0x80, + 0x1E, 0x27, 0xFC, 0x60, 0x07, 0x98, 0x82, 0x58, 0x01, 0xE0, 0x82, 0x46, 0x00, 0x79, 0x45, 0x79, + 0x00, 0x1E, 0x28, 0x87, 0x0F, 0x87, 0x94, 0x9E, 0x08, 0x81, 0xE2, 0x78, 0x08, 0x80, 0x79, 0xE0, + 0x08, 0x80, 0x1F, 0x80, 0x08, 0x80, 0x06, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, + 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char path_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, + 0x07, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0x80, + 0x1F, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, + 0x00, 0x1F, 0xFF, 0xFF, 0x0F, 0x87, 0xFF, 0xFE, 0x0F, 0x81, 0xFF, 0xF8, 0x0F, 0x80, 0x7F, 0xE0, + 0x0F, 0x80, 0x1F, 0x80, 0x0F, 0x80, 0x06, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char dig_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xA4, + 0x00, 0x00, 0x01, 0x52, 0x00, 0x00, 0x02, 0x8B, 0x00, 0x00, 0x02, 0x96, 0x00, 0x00, 0x02, 0x6C, + 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x08, 0xF0, 0x00, 0x00, 0x11, 0x80, 0x00, 0x03, 0x2A, 0x00, + 0x00, 0x04, 0xC6, 0x00, 0x00, 0x09, 0x8C, 0x00, 0x00, 0x15, 0x18, 0x00, 0x00, 0x22, 0x30, 0x00, + 0x00, 0x24, 0x78, 0x00, 0x0F, 0xC5, 0xE4, 0x00, 0x08, 0xC7, 0xC4, 0x00, 0x08, 0xC3, 0x28, 0x00, + 0x08, 0xA0, 0x10, 0x00, 0x08, 0x90, 0x20, 0x00, 0x08, 0x88, 0xC0, 0x00, 0x08, 0x87, 0x00, 0x00, + 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char dig_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x01, 0xDE, 0x00, 0x00, 0x03, 0x8F, 0x00, 0x00, 0x03, 0x9E, 0x00, 0x00, 0x03, 0xFC, + 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x03, 0x3E, 0x00, + 0x00, 0x07, 0xFE, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x3F, 0xF0, 0x00, + 0x00, 0x3F, 0xF8, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xF8, 0x00, + 0x0F, 0xBF, 0xF0, 0x00, 0x0F, 0x9F, 0xE0, 0x00, 0x0F, 0x8F, 0xC0, 0x00, 0x0F, 0x87, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char water_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x82, 0x00, + 0x08, 0x20, 0x82, 0x00, 0x14, 0x51, 0x45, 0x00, 0x63, 0x8E, 0x38, 0xC0, 0x88, 0x20, 0x82, 0x20, + 0x77, 0xDF, 0x7D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x08, 0x00, 0x20, 0x82, 0x08, + 0x00, 0x51, 0x45, 0x14, 0x00, 0x8E, 0x38, 0xE2, 0x0F, 0xA0, 0x82, 0x09, 0x08, 0xDF, 0x7D, 0xF6, + 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x82, 0x00, 0x08, 0x80, 0x82, 0x00, 0x08, 0x81, 0x45, 0x00, + 0x08, 0x86, 0x38, 0xC0, 0xF8, 0xF8, 0x82, 0x20, 0x40, 0x17, 0x7D, 0xC0, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char water_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x82, 0x00, + 0x08, 0x20, 0x82, 0x00, 0x1C, 0x71, 0xC7, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, + 0x77, 0xDF, 0x7D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x08, 0x00, 0x20, 0x82, 0x08, + 0x00, 0x71, 0xC7, 0x1C, 0x00, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xDF, 0x7D, 0xF6, + 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x82, 0x00, 0x0F, 0x80, 0x82, 0x00, 0x0F, 0x81, 0xC7, 0x00, + 0x0F, 0x87, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xF7, 0x7D, 0xC0, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char house_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xF0, 0x00, 0x00, 0x2A, 0x10, + 0x00, 0x00, 0x45, 0xE0, 0x00, 0x00, 0x93, 0x20, 0x00, 0x01, 0x19, 0x20, 0x00, 0x02, 0x0C, 0x20, + 0x00, 0x04, 0x7E, 0x20, 0x00, 0x08, 0x03, 0x20, 0x00, 0x10, 0xFF, 0x90, 0x00, 0x20, 0x00, 0xC8, + 0x00, 0x47, 0xFF, 0xE4, 0x00, 0xF0, 0x00, 0x7E, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, + 0x00, 0x11, 0xEF, 0xD0, 0x00, 0x11, 0x28, 0x50, 0x0F, 0x91, 0x28, 0x50, 0x08, 0x91, 0x28, 0x50, + 0x08, 0x91, 0x2F, 0xD0, 0x08, 0x91, 0x20, 0x10, 0x08, 0x91, 0x20, 0x10, 0x08, 0x9F, 0xFF, 0xF0, + 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char house_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xF0, 0x00, 0x00, 0x3B, 0xF0, + 0x00, 0x00, 0x7D, 0xE0, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xE0, + 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF8, + 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xF0, + 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0x38, 0x70, 0x0F, 0x9F, 0x38, 0x70, 0x0F, 0x9F, 0x38, 0x70, + 0x0F, 0x9F, 0x3F, 0xF0, 0x0F, 0x9F, 0x3F, 0xF0, 0x0F, 0x9F, 0x3F, 0xF0, 0x0F, 0x9F, 0xFF, 0xF0, + 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char volcano_down_cursor_data[32 * 4] = { + 0x00, 0x08, 0xA0, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, + 0x00, 0x07, 0xB0, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x17, 0x84, 0x00, 0x00, 0x30, 0x1E, 0x00, + 0x00, 0x76, 0x72, 0x00, 0x00, 0x5A, 0x89, 0x00, 0x00, 0x81, 0x1C, 0x80, 0x03, 0x08, 0x0A, 0x70, + 0x04, 0x18, 0x17, 0x88, 0x18, 0x30, 0x0A, 0xA6, 0x23, 0xC2, 0x07, 0x7F, 0x7C, 0x5F, 0x8F, 0xEC, + 0x40, 0xF0, 0xD8, 0xC0, 0x00, 0x40, 0x20, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, + 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, + 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char volcano_down_cursor_mask[32 * 4] = { + 0x00, 0x08, 0xA0, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, + 0x00, 0x07, 0xB0, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, + 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xF0, + 0x07, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0x7C, 0x7F, 0xFF, 0xEC, + 0x40, 0xF0, 0xF8, 0xC0, 0x00, 0x40, 0x20, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char walk_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, + 0x02, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, + 0x00, 0x12, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x1C, 0x00, + 0x02, 0x20, 0x22, 0x00, 0x02, 0x10, 0x21, 0x00, 0x01, 0x08, 0x10, 0x80, 0x00, 0x88, 0x08, 0x80, + 0x00, 0x72, 0x07, 0x20, 0x00, 0x0D, 0x00, 0xD0, 0x0F, 0x89, 0x00, 0x90, 0x08, 0x86, 0x00, 0x60, + 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x0E, 0x00, 0x08, 0x80, 0x11, 0x00, 0x08, 0x80, 0x10, 0x80, + 0x08, 0x80, 0x08, 0x40, 0xF8, 0xF8, 0x04, 0x40, 0x40, 0x10, 0x03, 0x90, 0x20, 0x20, 0x00, 0x68, + 0x10, 0x40, 0x00, 0x48, 0x08, 0x80, 0x00, 0x30, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char walk_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, + 0x03, 0xF0, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x1C, 0x00, + 0x03, 0xE0, 0x3E, 0x00, 0x03, 0xF0, 0x3F, 0x00, 0x01, 0xF8, 0x1F, 0x80, 0x00, 0xF8, 0x0F, 0x80, + 0x00, 0x72, 0x07, 0x20, 0x00, 0x0F, 0x00, 0xF0, 0x0F, 0x8F, 0x00, 0xF0, 0x0F, 0x86, 0x00, 0x60, + 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x0E, 0x00, 0x0F, 0x80, 0x1F, 0x00, 0x0F, 0x80, 0x1F, 0x80, + 0x0F, 0x80, 0x0F, 0xC0, 0xFF, 0xF8, 0x07, 0xC0, 0x7F, 0xF0, 0x03, 0x90, 0x3F, 0xE0, 0x00, 0x78, + 0x1F, 0xC0, 0x00, 0x78, 0x0F, 0x80, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char paint_down_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFA, + 0x00, 0x00, 0x01, 0xF6, 0x00, 0x00, 0x03, 0xE4, 0x00, 0x03, 0x07, 0xCC, 0x00, 0x07, 0x84, 0x98, + 0x00, 0x0F, 0xC8, 0x70, 0x00, 0x1B, 0xF8, 0x60, 0x00, 0x3D, 0xE0, 0xC0, 0x00, 0x7E, 0xE3, 0x00, + 0x00, 0xFF, 0x62, 0x00, 0x00, 0xDF, 0xBE, 0x00, 0x00, 0x7F, 0xDF, 0x00, 0x00, 0x37, 0xEF, 0x80, + 0x00, 0x1B, 0xF7, 0xC0, 0x07, 0xCF, 0xFB, 0xC0, 0x04, 0x46, 0x9D, 0xC0, 0x04, 0x43, 0x07, 0x80, + 0x04, 0x41, 0x83, 0x00, 0x04, 0x40, 0xC6, 0x00, 0x04, 0x40, 0x6C, 0x00, 0x04, 0x40, 0x28, 0x00, + 0x7C, 0x7C, 0x10, 0x00, 0x20, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, + 0x04, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +unsigned char paint_down_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x03, 0x07, 0xFC, 0x00, 0x07, 0x87, 0xF8, + 0x00, 0x0F, 0xCF, 0xF0, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0x80, + 0x00, 0x1F, 0xFF, 0xC0, 0x07, 0xCF, 0xFF, 0xC0, 0x07, 0xC7, 0xFF, 0xC0, 0x07, 0xC3, 0xFF, 0x80, + 0x07, 0xC1, 0xFF, 0x00, 0x07, 0xC0, 0xFE, 0x00, 0x07, 0xC0, 0x7C, 0x00, 0x07, 0xC0, 0x38, 0x00, + 0x7F, 0xFC, 0x10, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, + 0x07, 0xC0, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +unsigned char entrance_down_cursor_data[32 * 4] = { + 0x20, 0x00, 0x00, 0x08, 0x50, 0x00, 0x00, 0x14, 0x88, 0x00, 0x00, 0x22, 0x50, 0x00, 0x00, 0x14, + 0x7F, 0xFF, 0xFF, 0xFC, 0x58, 0x00, 0x00, 0x34, 0x54, 0x00, 0x00, 0x54, 0x54, 0x00, 0x00, 0x54, + 0x54, 0x00, 0x00, 0x54, 0x5C, 0x00, 0x00, 0x34, 0x5F, 0xFF, 0xFF, 0xF4, 0x50, 0x00, 0x00, 0x14, + 0x50, 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x14, + 0x50, 0x00, 0x00, 0x14, 0x5F, 0x80, 0x00, 0x14, 0xD8, 0x80, 0x00, 0x14, 0x58, 0x80, 0x02, 0xB5, + 0x58, 0x80, 0x00, 0x14, 0xD8, 0x80, 0x00, 0x14, 0x58, 0x80, 0x05, 0x74, 0x08, 0x80, 0x00, 0x00, + 0x08, 0x80, 0x00, 0xD2, 0xF8, 0xF8, 0x0E, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; +unsigned char entrance_down_cursor_mask[32 * 4] = { + 0x20, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x1C, 0xF8, 0x00, 0x00, 0x3E, 0x70, 0x00, 0x00, 0x1C, + 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x77, 0xFF, 0xFF, 0xDC, 0x77, 0xFF, 0xFF, 0xDC, + 0x77, 0xFF, 0xFF, 0xDC, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x70, 0x00, 0x00, 0x1C, + 0x70, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x1C, + 0x70, 0x00, 0x00, 0x1C, 0x7F, 0x80, 0x00, 0x1C, 0xFF, 0x80, 0x00, 0x1C, 0x7F, 0x80, 0x02, 0xBD, + 0x7F, 0x80, 0x00, 0x1C, 0xFF, 0x80, 0x00, 0x1C, 0x7F, 0x80, 0x05, 0x7C, 0x0F, 0x80, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0xD2, 0xFF, 0xF8, 0x0E, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +}; + +unsigned char hand_open_cursor_data[32 * 4] = { + 0x00, 0x06, 0x10, 0x00, 0x00, 0x09, 0x38, 0x00, 0x00, 0x09, 0x24, 0x00, 0x03, 0x08, 0xA4, 0x00, + 0x04, 0x88, 0xA4, 0xC0, 0x04, 0x48, 0x63, 0x20, 0x04, 0x24, 0x63, 0x10, 0x06, 0x24, 0x61, 0x90, + 0x02, 0x14, 0x21, 0x90, 0x03, 0x0C, 0x21, 0x10, 0x01, 0x04, 0x21, 0x10, 0x01, 0x86, 0x01, 0x10, + 0x00, 0x82, 0x00, 0x08, 0x00, 0xC0, 0x00, 0x08, 0x00, 0x60, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, + 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, + 0x0F, 0xC0, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x08, + 0x0F, 0x0F, 0x00, 0x04, 0x01, 0xF9, 0x80, 0x04, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00, 0x7F, 0xE0, +}; +unsigned char hand_open_cursor_mask[32 * 4] = { + 0x00, 0x06, 0x10, 0x00, 0x00, 0x0F, 0x38, 0x00, 0x00, 0x0F, 0x3C, 0x00, 0x03, 0x0F, 0xBC, 0x00, + 0x07, 0x8F, 0xBC, 0xC0, 0x07, 0xCF, 0xFF, 0xE0, 0x07, 0xE7, 0xFF, 0xF0, 0x07, 0xE7, 0xFF, 0xF0, + 0x03, 0xF7, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xF0, + 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, + 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, + 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xF8, + 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0xF9, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xE0, +}; + +unsigned char hand_closed_cursor_data[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xE0, 0x00, 0x00, 0x43, 0x10, 0x00, 0x00, 0x41, 0x8C, 0x00, + 0x00, 0x20, 0x87, 0x00, 0x0E, 0x20, 0x42, 0x80, 0x11, 0x98, 0x62, 0x40, 0x10, 0x6C, 0x61, 0x20, + 0x18, 0x14, 0x21, 0x20, 0x0C, 0x0C, 0x21, 0x10, 0x06, 0x04, 0x21, 0x10, 0x03, 0x06, 0x01, 0x10, + 0x00, 0x82, 0x00, 0x08, 0x00, 0xC0, 0x00, 0x08, 0x00, 0x60, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, + 0x07, 0x10, 0x00, 0x10, 0x08, 0x90, 0x00, 0x10, 0x08, 0x60, 0x00, 0x10, 0x0A, 0x00, 0x00, 0x10, + 0x0A, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x03, 0x80, 0x00, 0x08, + 0x00, 0x7F, 0x00, 0x04, 0x00, 0x01, 0x80, 0x04, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00, 0x7F, 0xE0, +}; +unsigned char hand_closed_cursor_mask[32 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xE0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x7F, 0xFC, 0x00, + 0x00, 0x3F, 0xFF, 0x00, 0x0E, 0x3F, 0xFF, 0x80, 0x1F, 0x9F, 0xFF, 0xC0, 0x1F, 0xEF, 0xFF, 0xE0, + 0x1F, 0xF7, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0, + 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, + 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, + 0x07, 0x1F, 0xFF, 0xF0, 0x0F, 0x9F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF8, + 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xE0, +}; \ No newline at end of file diff --git a/src/cursors.h b/src/cursors.h index 531abf7e62..19b19a2448 100644 --- a/src/cursors.h +++ b/src/cursors.h @@ -21,571 +21,164 @@ #ifndef _CURSORS_H_ #define _CURSORS_H_ -#define NO_CURSORS 27 +enum { + CURSOR_ARROW = 0, + CURSOR_BLANK = 1, + CURSOR_UP_ARROW = 2, + CURSOR_UP_DOWN_ARROW = 3, + CURSOR_HAND_POINT = 4, + CURSOR_ZZZ = 5, + CURSOR_DIAGONAL_ARROWS = 6, + CURSOR_PICKER = 7, + CURSOR_TREE_DOWN = 8, + CURSOR_FOUNTAIN_DOWN = 9, + CURSOR_STATUE_DOWN = 10, + CURSOR_BENCH_DOWN = 11, + CURSOR_CROSS_HAIR = 12, + CURSOR_BIN_DOWN = 13, + CURSOR_LAMPPOST_DOWN = 14, + CURSOR_FENCE_DOWN = 15, + CURSOR_FLOWER_DOWN = 16, + CURSOR_PATH_DOWN = 17, + CURSOR_DIG_DOWN = 18, + CURSOR_WATER_DOWN = 19, + CURSOR_HOUSE_DOWN = 20, + CURSOR_VOLCANO_DOWN = 21, + CURSOR_WALK_DOWN = 22, + CURSOR_PAINT_DOWN = 23, + CURSOR_ENTRANCE_DOWN = 24, + CURSOR_HAND_OPEN = 25, + CURSOR_HAND_CLOSED = 26, + CURSOR_COUNT +}; -unsigned char blank_cursor_data[32 * 4] = { - 0 -}; -unsigned char blank_cursor_mask[32 * 4] = { - 0 -}; +extern unsigned char blank_cursor_data[32 * 4]; +extern unsigned char blank_cursor_mask[32 * 4]; #define BLANK_CURSOR_HOTX 0 #define BLANK_CURSOR_HOTY 0 -unsigned char up_arrow_cursor_data[32 * 4] = { - 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, - 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x02, 0x20, 0x00, - 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, - 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -unsigned char up_arrow_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00, - 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x03, 0xE0, 0x00, - 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, - 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; +extern unsigned char up_arrow_cursor_data[32 * 4]; +extern unsigned char up_arrow_cursor_mask[32 * 4]; #define UP_ARROW_CURSOR_HOTX 15 #define UP_ARROW_CURSOR_HOTY 0 -unsigned char up_down_arrow_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0xA0, 0x00, - 0x00, 0x05, 0x50, 0x00, 0x00, 0x0A, 0x28, 0x00, 0x00, 0x17, 0x74, 0x00, 0x00, 0x21, 0x42, 0x00, - 0x00, 0x1D, 0xDC, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00, - 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xE0, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0xD0, 0x00, 0x00, 0x1D, 0x5C, 0x00, - 0x00, 0x21, 0x42, 0x00, 0x00, 0x17, 0x74, 0x00, 0x00, 0x0A, 0x28, 0x00, 0x00, 0x05, 0x50, 0x00, - 0x00, 0x02, 0xA0, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -unsigned char up_down_arrow_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x03, 0xE0, 0x00, - 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x3F, 0x7E, 0x00, - 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x03, 0xE0, 0x00, - 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x1F, 0x7C, 0x00, - 0x00, 0x3F, 0x7E, 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x07, 0x70, 0x00, - 0x00, 0x03, 0xE0, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, -}; +extern unsigned char up_down_arrow_cursor_data[32 * 4]; +extern unsigned char up_down_arrow_cursor_mask[32 * 4]; #define UP_DOWN_ARROW_CURSOR_HOTX 7 #define UP_DOWN_ARROW_CURSOR_HOTY 31 -unsigned char zzz_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, - 0x00, 0x00, 0x03, 0xE2, 0x00, 0x00, 0xFC, 0x34, 0x00, 0x01, 0x07, 0x62, 0x00, 0x3F, 0xEA, 0xDC, - 0x00, 0x40, 0xD4, 0x20, 0x00, 0x3D, 0xBB, 0xC0, 0x3F, 0xCB, 0x04, 0x00, 0x40, 0x34, 0xF8, 0x00, - 0x40, 0x2F, 0x00, 0x00, 0x3C, 0x40, 0x80, 0x00, 0x08, 0xBF, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x23, 0xC0, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -unsigned char zzz_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, - 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFB, 0xDC, - 0x00, 0x7F, 0xF7, 0xE0, 0x00, 0x3F, 0xFB, 0xC0, 0x3F, 0xCF, 0xFC, 0x00, 0x7F, 0xFC, 0xF8, 0x00, - 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x0F, 0xBF, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, - 0x3F, 0xC0, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; +extern unsigned char zzz_cursor_data[32 * 4]; +extern unsigned char zzz_cursor_mask[32 * 4]; #define ZZZ_CURSOR_HOTX 0 #define ZZZ_CURSOR_HOTY 0 -unsigned char diagonal_arrow_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, - 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -unsigned char diagonal_arrow_cursor_mask[32 * 4] = { - 0xFE, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, - 0xFC, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, - 0x01, 0xC2, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, - 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; +extern unsigned char diagonal_arrow_cursor_data[32 * 4]; +extern unsigned char diagonal_arrow_cursor_mask[32 * 4]; #define DIAGONAL_ARROW_CURSOR_HOTX 0 #define DIAGONAL_ARROW_CURSOR_HOTY 0 -unsigned char picker_cursor_data[32 * 4] = { - 0x00, 0x07, 0xC0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x13, 0x30, 0x00, 0x00, 0x17, 0xB0, 0x00, - 0x00, 0x17, 0xB0, 0x00, 0x00, 0x13, 0x30, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x0F, 0xE0, 0x00, - 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x17, 0x30, 0x00, 0x00, 0x12, 0x30, 0x00, 0x00, 0x21, 0x18, 0x00, - 0x00, 0x23, 0x18, 0x00, 0x00, 0x44, 0x8C, 0x00, 0x00, 0x44, 0x8C, 0x00, 0x00, 0x88, 0x46, 0x00, - 0x00, 0x90, 0x26, 0x00, 0x01, 0x10, 0x23, 0x00, 0x01, 0x20, 0x13, 0x00, 0x02, 0x40, 0x09, 0x80, - 0x02, 0x40, 0x09, 0x80, 0x04, 0x80, 0x04, 0xC0, 0x04, 0x80, 0x04, 0xC0, 0x04, 0x80, 0x04, 0xC0, - 0x04, 0x80, 0x04, 0xC0, 0x04, 0x80, 0x04, 0xC0, 0x04, 0x40, 0x08, 0xC0, 0x02, 0x40, 0x09, 0x80, - 0x01, 0x20, 0x13, 0x00, 0x00, 0x90, 0x26, 0x00, 0x00, 0x68, 0x5C, 0x00, 0x00, 0x1C, 0xF0, 0x00, -}; -unsigned char picker_cursor_mask[32 * 4] = { - 0x00, 0x07, 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, - 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x0F, 0xE0, 0x00, - 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xF8, 0x00, - 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x7C, 0xFC, 0x00, 0x00, 0x7C, 0xFC, 0x00, 0x00, 0xF8, 0x7E, 0x00, - 0x00, 0xF0, 0x3E, 0x00, 0x01, 0xF0, 0x3F, 0x00, 0x01, 0xE0, 0x1F, 0x00, 0x03, 0xC0, 0x0F, 0x80, - 0x03, 0xC0, 0x0F, 0x80, 0x07, 0x80, 0x07, 0xC0, 0x07, 0x80, 0x07, 0xC0, 0x07, 0x80, 0x07, 0xC0, - 0x07, 0x80, 0x07, 0xC0, 0x07, 0x80, 0x07, 0xC0, 0x07, 0xC0, 0x0F, 0xC0, 0x03, 0xC0, 0x0F, 0x80, - 0x01, 0xE0, 0x1F, 0x00, 0x00, 0xF0, 0x3E, 0x00, 0x00, 0x78, 0x7C, 0x00, 0x00, 0x1C, 0xF0, 0x00, -}; +extern unsigned char picker_cursor_data[32 * 4]; +extern unsigned char picker_cursor_mask[32 * 4]; #define PICKER_CURSOR_HOTX 15 #define PICKER_CURSOR_HOTY 31 -unsigned char tree_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0x89, 0xC0, 0x00, 0x02, 0x06, 0x20, - 0x00, 0x07, 0x00, 0x18, 0x00, 0x07, 0x40, 0x04, 0x00, 0x03, 0x80, 0x04, 0x00, 0x01, 0xC0, 0x02, - 0x00, 0x03, 0x82, 0x02, 0x00, 0x03, 0xD0, 0x04, 0x00, 0x07, 0xF9, 0x08, 0x00, 0x0F, 0x6E, 0x04, - 0x00, 0x0E, 0xB8, 0x82, 0x00, 0x0F, 0x44, 0x22, 0x00, 0x0F, 0xA8, 0x46, 0x00, 0x0F, 0xFC, 0x16, - 0x00, 0x07, 0xEE, 0x8C, 0x0F, 0x81, 0xFF, 0xD8, 0x08, 0x80, 0x7D, 0xF0, 0x08, 0x80, 0x3A, 0x00, - 0x08, 0x80, 0x1A, 0x00, 0x08, 0x80, 0x1A, 0x00, 0x08, 0x80, 0x12, 0x00, 0x08, 0x80, 0x12, 0x00, - 0x08, 0x80, 0x11, 0x00, 0xF8, 0xF8, 0x60, 0x80, 0x40, 0x11, 0x80, 0x60, 0x20, 0x22, 0x09, 0x90, - 0x10, 0x41, 0xD5, 0x60, 0x08, 0x80, 0x22, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char tree_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xF9, 0xC0, 0x00, 0x03, 0xFF, 0xE0, - 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFE, - 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFC, - 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x07, 0xFF, 0xFC, 0x0F, 0x81, 0xFF, 0xF8, 0x0F, 0x80, 0x7F, 0xF0, 0x0F, 0x80, 0x3E, 0x00, - 0x0F, 0x80, 0x1E, 0x00, 0x0F, 0x80, 0x1E, 0x00, 0x0F, 0x80, 0x1E, 0x00, 0x0F, 0x80, 0x1E, 0x00, - 0x0F, 0x80, 0x1F, 0x00, 0xFF, 0xF8, 0x7F, 0x80, 0x7F, 0xF1, 0xFF, 0xE0, 0x3F, 0xE3, 0xFF, 0xF0, - 0x1F, 0xC1, 0xF7, 0x60, 0x0F, 0x80, 0x22, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char tree_down_cursor_data[32 * 4]; +extern unsigned char tree_down_cursor_mask[32 * 4]; #define TREE_DOWN_CURSOR_HOTX 7 #define TREE_DOWN_CURSOR_HOTY 31 -unsigned char fountain_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x00, - 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x7B, 0xC0, 0x00, 0x01, 0x8B, 0x30, 0x00, 0x02, 0x17, 0xC8, - 0x00, 0x02, 0x0F, 0x88, 0x0F, 0x83, 0x80, 0x38, 0x08, 0x82, 0x7F, 0xD8, 0x08, 0x81, 0x01, 0xF0, - 0x08, 0x80, 0xE3, 0xE0, 0x08, 0x80, 0x3F, 0x80, 0x08, 0x80, 0x17, 0x00, 0x08, 0x80, 0x13, 0x00, - 0x08, 0x80, 0x13, 0x00, 0xF8, 0xF8, 0x27, 0x80, 0x40, 0x10, 0x4E, 0xC0, 0x20, 0x20, 0x80, 0xE0, - 0x10, 0x40, 0xC1, 0xA0, 0x08, 0x80, 0x7F, 0xC0, 0x05, 0x00, 0x1F, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char fountain_down_cursor_mask[32 * 4] = { - 0x00, 0x01, 0x04, 0x00, 0x00, 0x10, 0x10, 0x81, 0x00, 0x00, 0x41, 0x14, 0x00, 0x05, 0x08, 0x20, - 0x00, 0x00, 0x22, 0x81, 0x00, 0x00, 0x88, 0x10, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xF8, - 0x00, 0x03, 0xFF, 0xF8, 0x0F, 0x83, 0xFF, 0xF8, 0x0F, 0x83, 0xFF, 0xF8, 0x0F, 0x81, 0xFF, 0xF0, - 0x0F, 0x80, 0xFF, 0xE0, 0x0F, 0x80, 0x3F, 0x80, 0x0F, 0x80, 0x1F, 0x00, 0x0F, 0x80, 0x1F, 0x00, - 0x0F, 0x80, 0x1F, 0x00, 0xFF, 0xF8, 0x3F, 0x80, 0x7F, 0xF0, 0x7F, 0xC0, 0x3F, 0xE0, 0xFF, 0xE0, - 0x1F, 0xC0, 0xFF, 0xE0, 0x0F, 0x80, 0x7F, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char fountain_down_cursor_data[32 * 4]; +extern unsigned char fountain_down_cursor_mask[32 * 4]; #define FOUNTAIN_DOWN_CURSOR_HOTX 7 #define FOUNTAIN_DOWN_CURSOR_HOTY 31 -unsigned char statue_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x07, 0x03, 0x30, - 0x00, 0x02, 0x84, 0x98, 0x00, 0x01, 0x44, 0x98, 0x00, 0x00, 0xB5, 0xA8, 0x00, 0x00, 0x4A, 0xD0, - 0x00, 0x00, 0x21, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x10, 0x80, - 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x0F, 0x80, 0x08, 0x80, 0x08, 0x80, 0x04, 0x80, 0x08, 0x80, 0x05, 0x00, - 0x08, 0x80, 0x0D, 0x00, 0x08, 0x80, 0x09, 0x00, 0x08, 0x80, 0x3F, 0x80, 0x08, 0x80, 0x20, 0x80, - 0x08, 0x80, 0x20, 0x80, 0xF8, 0xF8, 0x20, 0x80, 0x40, 0x10, 0x20, 0x80, 0x20, 0x20, 0x20, 0x80, - 0x10, 0x40, 0x7F, 0xC0, 0x08, 0x80, 0x80, 0x20, 0x05, 0x00, 0xFF, 0xE0, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char statue_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x07, 0x03, 0x30, - 0x00, 0x03, 0x87, 0x98, 0x00, 0x01, 0xC7, 0x98, 0x00, 0x00, 0xF7, 0xB8, 0x00, 0x00, 0x7E, 0xF0, - 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x1F, 0x80, - 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x07, 0x80, 0x0F, 0x80, 0x07, 0x00, - 0x0F, 0x80, 0x0F, 0x00, 0x0F, 0x80, 0x0F, 0x00, 0x0F, 0x80, 0x3F, 0x80, 0x0F, 0x80, 0x3F, 0x80, - 0x0F, 0x80, 0x3F, 0x80, 0xFF, 0xF8, 0x3F, 0x80, 0x7F, 0xF0, 0x3F, 0x80, 0x3F, 0xE0, 0x3F, 0x80, - 0x1F, 0xC0, 0x7F, 0xC0, 0x0F, 0x80, 0xFF, 0xE0, 0x07, 0x00, 0xFF, 0xE0, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char statue_down_cursor_data[32 * 4]; +extern unsigned char statue_down_cursor_mask[32 * 4]; #define STATUE_DOWN_CURSOR_HOTX 7 #define STATUE_DOWN_CURSOR_HOTY 31 -unsigned char bench_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x80, 0x00, - 0x00, 0x04, 0x60, 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x05, 0x81, 0x80, - 0x00, 0x05, 0x60, 0x60, 0x00, 0x0D, 0x18, 0x18, 0x00, 0x33, 0x06, 0x04, 0x00, 0xC0, 0xC1, 0x84, - 0x00, 0xF0, 0x30, 0x64, 0x00, 0xAC, 0x0C, 0x1C, 0x00, 0xA7, 0x03, 0x14, 0x00, 0x40, 0xC0, 0xD4, - 0x00, 0x00, 0xF0, 0x34, 0x0F, 0x80, 0xAC, 0x0C, 0x08, 0x80, 0xA3, 0x3C, 0x08, 0x80, 0x41, 0xD4, - 0x08, 0x80, 0x01, 0xD4, 0x08, 0x80, 0x01, 0x48, 0x08, 0x80, 0x01, 0x40, 0x08, 0x80, 0x00, 0x80, - 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char bench_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, - 0x00, 0x07, 0xE0, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0x80, - 0x00, 0x07, 0x7F, 0xE0, 0x00, 0x0F, 0x1F, 0xF8, 0x00, 0x3F, 0x07, 0xFC, 0x00, 0xFF, 0xC1, 0xFC, - 0x00, 0xFF, 0xF0, 0x7C, 0x00, 0xEF, 0xFC, 0x1C, 0x00, 0xE7, 0xFF, 0x1C, 0x00, 0x40, 0xFF, 0xDC, - 0x00, 0x00, 0xFF, 0xFC, 0x0F, 0x80, 0xEF, 0xFC, 0x0F, 0x80, 0xE3, 0xFC, 0x0F, 0x80, 0x41, 0xDC, - 0x0F, 0x80, 0x01, 0xDC, 0x0F, 0x80, 0x01, 0xC8, 0x0F, 0x80, 0x01, 0xC0, 0x0F, 0x80, 0x00, 0x80, - 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char bench_down_cursor_data[32 * 4]; +extern unsigned char bench_down_cursor_mask[32 * 4]; #define BENCH_DOWN_CURSOR_HOTX 7 #define BENCH_DOWN_CURSOR_HOTY 31 -unsigned char cross_hair_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE2, 0x3F, 0x80, - 0x10, 0x15, 0x40, 0x40, 0x0F, 0xE2, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -unsigned char cross_hair_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE2, 0x3F, 0x80, - 0x1F, 0xF7, 0x7F, 0xC0, 0x0F, 0xE2, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; +extern unsigned char cross_hair_cursor_data[32 * 4]; +extern unsigned char cross_hair_cursor_mask[32 * 4]; #define CROSS_HAIR_CURSOR_HOTX 15 #define CROSS_HAIR_CURSOR_HOTY 15 -unsigned char bin_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x22, 0x00, - 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xC3, 0x80, 0x00, 0x01, 0x00, 0xC0, 0x00, 0x02, 0x57, 0xE0, - 0x00, 0x02, 0x00, 0x60, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x01, 0x01, 0xC0, 0x00, 0x01, 0x40, 0xC0, - 0x00, 0x01, 0x50, 0xC0, 0x0F, 0x81, 0x50, 0x40, 0x08, 0x81, 0x51, 0x40, 0x08, 0x81, 0x51, 0x40, - 0x08, 0x81, 0x55, 0x40, 0x08, 0x81, 0x55, 0x40, 0x08, 0x81, 0x55, 0x40, 0x08, 0x81, 0x55, 0x40, - 0x08, 0x81, 0x55, 0x40, 0xF8, 0xF9, 0x55, 0x40, 0x40, 0x11, 0x55, 0x40, 0x20, 0x21, 0xFF, 0xC0, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char bin_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x22, 0x00, - 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xE0, - 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xC0, - 0x00, 0x01, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, - 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, 0x0F, 0x81, 0xFF, 0xC0, - 0x0F, 0x81, 0xFF, 0xC0, 0xFF, 0xF9, 0xFF, 0xC0, 0x7F, 0xF1, 0xFF, 0xC0, 0x3F, 0xE1, 0xFF, 0xC0, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char bin_down_cursor_data[32 * 4]; +extern unsigned char bin_down_cursor_mask[32 * 4]; #define BIN_DOWN_CURSOR_HOTX 7 #define BIN_DOWN_CURSOR_HOTY 31 -unsigned char lamppost_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xFF, 0x80, - 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x32, 0x00, - 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x94, 0x80, - 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x00, 0x94, 0x80, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, - 0x00, 0x00, 0x14, 0x00, 0x0F, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, - 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x14, 0x00, 0x08, 0x80, 0x1C, 0x00, - 0x08, 0x80, 0x1C, 0x00, 0xF8, 0xF8, 0x32, 0x00, 0x40, 0x10, 0x61, 0x00, 0x20, 0x20, 0x61, 0x00, - 0x10, 0x40, 0x71, 0x00, 0x08, 0x80, 0x7D, 0x00, 0x05, 0x00, 0xFF, 0x80, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char lamppost_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0x80, - 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3E, 0x00, - 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x9C, 0x80, - 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x00, 0x9C, 0x80, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x00, - 0x00, 0x00, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, - 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x1C, 0x00, - 0x0F, 0x80, 0x1C, 0x00, 0xFF, 0xF8, 0x3E, 0x00, 0x7F, 0xF0, 0x7F, 0x00, 0x3F, 0xE0, 0x7F, 0x00, - 0x1F, 0xC0, 0x7F, 0x00, 0x0F, 0x80, 0x7F, 0x00, 0x07, 0x00, 0xFF, 0x80, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char lamppost_down_cursor_data[32 * 4]; +extern unsigned char lamppost_down_cursor_mask[32 * 4]; #define LAMPPOST_DOWN_CURSOR_HOTX 7 #define LAMPPOST_DOWN_CURSOR_HOTY 31 -unsigned char fence_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x4E, 0x60, 0x00, 0x00, - 0x43, 0xB0, 0x00, 0x00, 0x20, 0xB1, 0x80, 0x00, 0x2C, 0x3A, 0xC0, 0x00, 0x2F, 0x0E, 0xC6, 0x00, - 0x2C, 0x82, 0xCB, 0x00, 0x2C, 0xB0, 0x6B, 0x18, 0x6C, 0xBC, 0x1B, 0x2C, 0x7C, 0xB2, 0x83, 0x2C, - 0x1E, 0xB2, 0xE1, 0xAC, 0x07, 0xB2, 0xD8, 0x6C, 0x01, 0xF2, 0xCA, 0x0C, 0x00, 0x7A, 0xCB, 0x86, - 0x00, 0x1E, 0xCB, 0x66, 0x0F, 0x87, 0xCB, 0x2E, 0x08, 0x81, 0xEB, 0x2C, 0x08, 0x80, 0x7B, 0x2C, - 0x08, 0x80, 0x1F, 0x2C, 0x08, 0x80, 0x07, 0xAC, 0x08, 0x80, 0x01, 0xEC, 0x08, 0x80, 0x00, 0x78, - 0x08, 0x80, 0x00, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char fence_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x7E, 0x60, 0x00, 0x00, - 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xF1, 0x80, 0x00, 0x3F, 0xFB, 0xC0, 0x00, 0x3F, 0xFF, 0xC6, 0x00, - 0x3C, 0xFF, 0xCF, 0x00, 0x3C, 0xFF, 0xEF, 0x18, 0x7C, 0xFF, 0xFF, 0x3C, 0x7C, 0xF3, 0xFF, 0x3C, - 0x1E, 0xF3, 0xFF, 0xBC, 0x07, 0xF3, 0xDF, 0xFC, 0x01, 0xF3, 0xCF, 0xFC, 0x00, 0x7B, 0xCF, 0xFE, - 0x00, 0x1F, 0xCF, 0x7E, 0x0F, 0x87, 0xCF, 0x3E, 0x0F, 0x81, 0xEF, 0x3C, 0x0F, 0x80, 0x7F, 0x3C, - 0x0F, 0x80, 0x1F, 0x3C, 0x0F, 0x80, 0x07, 0xBC, 0x0F, 0x80, 0x01, 0xFC, 0x0F, 0x80, 0x00, 0x78, - 0x0F, 0x80, 0x00, 0x18, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char fence_down_cursor_data[32 * 4]; +extern unsigned char fence_down_cursor_mask[32 * 4]; #define FENCE_DOWN_CURSOR_HOTX 7 #define FENCE_DOWN_CURSOR_HOTY 31 -unsigned char flower_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x18, 0x44, 0x30, - 0x00, 0x24, 0x54, 0x48, 0x00, 0x22, 0x54, 0x88, 0x00, 0x11, 0x55, 0x10, 0x00, 0x0A, 0xBA, 0xA0, - 0x00, 0x05, 0xBB, 0x40, 0x00, 0x03, 0xC7, 0x80, 0x00, 0x7C, 0x92, 0x7C, 0x00, 0x83, 0x47, 0x82, - 0x01, 0x1D, 0x89, 0xF1, 0x00, 0x83, 0x23, 0x82, 0x00, 0x7C, 0x8A, 0x7C, 0x00, 0x03, 0xE7, 0x80, - 0x00, 0x05, 0xBB, 0x40, 0x0F, 0x8A, 0xBA, 0xA0, 0x08, 0x91, 0x55, 0x10, 0x08, 0x92, 0x54, 0x90, - 0x08, 0x8C, 0x44, 0x6C, 0x08, 0x98, 0x44, 0x32, 0x08, 0xA6, 0x44, 0x42, 0x08, 0xA1, 0x28, 0x82, - 0x08, 0xA0, 0xB9, 0x24, 0xF8, 0xFA, 0xBA, 0x44, 0x40, 0x11, 0x6A, 0x88, 0x20, 0x28, 0xED, 0x10, - 0x10, 0x46, 0x4A, 0x60, 0x08, 0x81, 0x81, 0x80, 0x05, 0x00, 0x7E, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char flower_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x18, 0x7C, 0x30, - 0x00, 0x3C, 0x7C, 0x78, 0x00, 0x3E, 0x7C, 0xF8, 0x00, 0x1F, 0x7D, 0xF0, 0x00, 0x0F, 0xBB, 0xE0, - 0x00, 0x07, 0xBB, 0xC0, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x7C, 0xFE, 0x7C, 0x00, 0xFF, 0xFF, 0xFE, - 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x7C, 0xFE, 0x7C, 0x00, 0x03, 0xFF, 0x80, - 0x00, 0x07, 0xBB, 0xC0, 0x0F, 0x8F, 0xBB, 0xE0, 0x0F, 0x9F, 0x7D, 0xF0, 0x0F, 0x9E, 0x7C, 0xF0, - 0x0F, 0x8C, 0x7C, 0x6C, 0x0F, 0x98, 0x7C, 0x3E, 0x0F, 0xBE, 0x7C, 0x7E, 0x0F, 0xBF, 0x38, 0xFE, - 0x0F, 0xBF, 0xB9, 0xFC, 0xFF, 0xFF, 0xBB, 0xFC, 0x7F, 0xFF, 0xFB, 0xF8, 0x3F, 0xEF, 0xFF, 0xF0, - 0x1F, 0xC7, 0xFF, 0xE0, 0x0F, 0x81, 0xFF, 0x80, 0x07, 0x00, 0x7E, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char flower_down_cursor_data[32 * 4]; +extern unsigned char flower_down_cursor_mask[32 * 4]; #define FLOWER_DOWN_CURSOR_HOTX 7 #define FLOWER_DOWN_CURSOR_HOTY 31 -unsigned char path_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x01, 0x85, 0x80, 0x00, - 0x06, 0x48, 0x60, 0x00, 0x1A, 0x24, 0x58, 0x00, 0x62, 0x3A, 0x46, 0x00, 0x79, 0xC1, 0x45, 0x80, - 0x1E, 0x27, 0xFC, 0x60, 0x07, 0x98, 0x82, 0x58, 0x01, 0xE0, 0x82, 0x46, 0x00, 0x79, 0x45, 0x79, - 0x00, 0x1E, 0x28, 0x87, 0x0F, 0x87, 0x94, 0x9E, 0x08, 0x81, 0xE2, 0x78, 0x08, 0x80, 0x79, 0xE0, - 0x08, 0x80, 0x1F, 0x80, 0x08, 0x80, 0x06, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, - 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char path_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, - 0x07, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, - 0x00, 0x1F, 0xFF, 0xFF, 0x0F, 0x87, 0xFF, 0xFE, 0x0F, 0x81, 0xFF, 0xF8, 0x0F, 0x80, 0x7F, 0xE0, - 0x0F, 0x80, 0x1F, 0x80, 0x0F, 0x80, 0x06, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, - 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char path_down_cursor_data[32 * 4]; +extern unsigned char path_down_cursor_mask[32 * 4]; #define PATH_DOWN_CURSOR_HOTX 7 #define PATH_DOWN_CURSOR_HOTY 31 -unsigned char dig_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xA4, - 0x00, 0x00, 0x01, 0x52, 0x00, 0x00, 0x02, 0x8B, 0x00, 0x00, 0x02, 0x96, 0x00, 0x00, 0x02, 0x6C, - 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x08, 0xF0, 0x00, 0x00, 0x11, 0x80, 0x00, 0x03, 0x2A, 0x00, - 0x00, 0x04, 0xC6, 0x00, 0x00, 0x09, 0x8C, 0x00, 0x00, 0x15, 0x18, 0x00, 0x00, 0x22, 0x30, 0x00, - 0x00, 0x24, 0x78, 0x00, 0x0F, 0xC5, 0xE4, 0x00, 0x08, 0xC7, 0xC4, 0x00, 0x08, 0xC3, 0x28, 0x00, - 0x08, 0xA0, 0x10, 0x00, 0x08, 0x90, 0x20, 0x00, 0x08, 0x88, 0xC0, 0x00, 0x08, 0x87, 0x00, 0x00, - 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char dig_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xFC, - 0x00, 0x00, 0x01, 0xDE, 0x00, 0x00, 0x03, 0x8F, 0x00, 0x00, 0x03, 0x9E, 0x00, 0x00, 0x03, 0xFC, - 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x03, 0x3E, 0x00, - 0x00, 0x07, 0xFE, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x3F, 0xF0, 0x00, - 0x00, 0x3F, 0xF8, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xF8, 0x00, - 0x0F, 0xBF, 0xF0, 0x00, 0x0F, 0x9F, 0xE0, 0x00, 0x0F, 0x8F, 0xC0, 0x00, 0x0F, 0x87, 0x00, 0x00, - 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char dig_down_cursor_data[32 * 4]; +extern unsigned char dig_down_cursor_mask[32 * 4]; #define DIG_DOWN_CURSOR_HOTX 7 #define DIG_DOWN_CURSOR_HOTY 31 -unsigned char water_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x82, 0x00, - 0x08, 0x20, 0x82, 0x00, 0x14, 0x51, 0x45, 0x00, 0x63, 0x8E, 0x38, 0xC0, 0x88, 0x20, 0x82, 0x20, - 0x77, 0xDF, 0x7D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x08, 0x00, 0x20, 0x82, 0x08, - 0x00, 0x51, 0x45, 0x14, 0x00, 0x8E, 0x38, 0xE2, 0x0F, 0xA0, 0x82, 0x09, 0x08, 0xDF, 0x7D, 0xF6, - 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x82, 0x00, 0x08, 0x80, 0x82, 0x00, 0x08, 0x81, 0x45, 0x00, - 0x08, 0x86, 0x38, 0xC0, 0xF8, 0xF8, 0x82, 0x20, 0x40, 0x17, 0x7D, 0xC0, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char water_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x82, 0x00, - 0x08, 0x20, 0x82, 0x00, 0x1C, 0x71, 0xC7, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, - 0x77, 0xDF, 0x7D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x08, 0x00, 0x20, 0x82, 0x08, - 0x00, 0x71, 0xC7, 0x1C, 0x00, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xDF, 0x7D, 0xF6, - 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x82, 0x00, 0x0F, 0x80, 0x82, 0x00, 0x0F, 0x81, 0xC7, 0x00, - 0x0F, 0x87, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xF7, 0x7D, 0xC0, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char water_down_cursor_data[32 * 4]; +extern unsigned char water_down_cursor_mask[32 * 4]; #define WATER_DOWN_CURSOR_HOTX 7 #define WATER_DOWN_CURSOR_HOTY 31 -unsigned char house_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xF0, 0x00, 0x00, 0x2A, 0x10, - 0x00, 0x00, 0x45, 0xE0, 0x00, 0x00, 0x93, 0x20, 0x00, 0x01, 0x19, 0x20, 0x00, 0x02, 0x0C, 0x20, - 0x00, 0x04, 0x7E, 0x20, 0x00, 0x08, 0x03, 0x20, 0x00, 0x10, 0xFF, 0x90, 0x00, 0x20, 0x00, 0xC8, - 0x00, 0x47, 0xFF, 0xE4, 0x00, 0xF0, 0x00, 0x7E, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, - 0x00, 0x11, 0xEF, 0xD0, 0x00, 0x11, 0x28, 0x50, 0x0F, 0x91, 0x28, 0x50, 0x08, 0x91, 0x28, 0x50, - 0x08, 0x91, 0x2F, 0xD0, 0x08, 0x91, 0x20, 0x10, 0x08, 0x91, 0x20, 0x10, 0x08, 0x9F, 0xFF, 0xF0, - 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char house_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xF0, 0x00, 0x00, 0x3B, 0xF0, - 0x00, 0x00, 0x7D, 0xE0, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xE0, - 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xF0, - 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0x38, 0x70, 0x0F, 0x9F, 0x38, 0x70, 0x0F, 0x9F, 0x38, 0x70, - 0x0F, 0x9F, 0x3F, 0xF0, 0x0F, 0x9F, 0x3F, 0xF0, 0x0F, 0x9F, 0x3F, 0xF0, 0x0F, 0x9F, 0xFF, 0xF0, - 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char house_down_cursor_data[32 * 4]; +extern unsigned char house_down_cursor_mask[32 * 4]; #define HOUSE_DOWN_CURSOR_HOTX 7 #define HOUSE_DOWN_CURSOR_HOTY 31 -unsigned char volcano_down_cursor_data[32 * 4] = { - 0x00, 0x08, 0xA0, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, - 0x00, 0x07, 0xB0, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x17, 0x84, 0x00, 0x00, 0x30, 0x1E, 0x00, - 0x00, 0x76, 0x72, 0x00, 0x00, 0x5A, 0x89, 0x00, 0x00, 0x81, 0x1C, 0x80, 0x03, 0x08, 0x0A, 0x70, - 0x04, 0x18, 0x17, 0x88, 0x18, 0x30, 0x0A, 0xA6, 0x23, 0xC2, 0x07, 0x7F, 0x7C, 0x5F, 0x8F, 0xEC, - 0x40, 0xF0, 0xD8, 0xC0, 0x00, 0x40, 0x20, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, - 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, - 0x08, 0x80, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char volcano_down_cursor_mask[32 * 4] = { - 0x00, 0x08, 0xA0, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, - 0x00, 0x07, 0xB0, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, - 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xF0, - 0x07, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0x7C, 0x7F, 0xFF, 0xEC, - 0x40, 0xF0, 0xF8, 0xC0, 0x00, 0x40, 0x20, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, - 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, - 0x0F, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char volcano_down_cursor_data[32 * 4]; +extern unsigned char volcano_down_cursor_mask[32 * 4]; #define VOLCANO_DOWN_CURSOR_HOTX 7 #define VOLCANO_DOWN_CURSOR_HOTY 31 -unsigned char walk_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, - 0x02, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, - 0x00, 0x12, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x1C, 0x00, - 0x02, 0x20, 0x22, 0x00, 0x02, 0x10, 0x21, 0x00, 0x01, 0x08, 0x10, 0x80, 0x00, 0x88, 0x08, 0x80, - 0x00, 0x72, 0x07, 0x20, 0x00, 0x0D, 0x00, 0xD0, 0x0F, 0x89, 0x00, 0x90, 0x08, 0x86, 0x00, 0x60, - 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x0E, 0x00, 0x08, 0x80, 0x11, 0x00, 0x08, 0x80, 0x10, 0x80, - 0x08, 0x80, 0x08, 0x40, 0xF8, 0xF8, 0x04, 0x40, 0x40, 0x10, 0x03, 0x90, 0x20, 0x20, 0x00, 0x68, - 0x10, 0x40, 0x00, 0x48, 0x08, 0x80, 0x00, 0x30, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char walk_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, - 0x03, 0xF0, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, - 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x1C, 0x00, - 0x03, 0xE0, 0x3E, 0x00, 0x03, 0xF0, 0x3F, 0x00, 0x01, 0xF8, 0x1F, 0x80, 0x00, 0xF8, 0x0F, 0x80, - 0x00, 0x72, 0x07, 0x20, 0x00, 0x0F, 0x00, 0xF0, 0x0F, 0x8F, 0x00, 0xF0, 0x0F, 0x86, 0x00, 0x60, - 0x0F, 0x80, 0x00, 0x00, 0x0F, 0x80, 0x0E, 0x00, 0x0F, 0x80, 0x1F, 0x00, 0x0F, 0x80, 0x1F, 0x80, - 0x0F, 0x80, 0x0F, 0xC0, 0xFF, 0xF8, 0x07, 0xC0, 0x7F, 0xF0, 0x03, 0x90, 0x3F, 0xE0, 0x00, 0x78, - 0x1F, 0xC0, 0x00, 0x78, 0x0F, 0x80, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char walk_down_cursor_data[32 * 4]; +extern unsigned char walk_down_cursor_mask[32 * 4]; #define WALK_DOWN_CURSOR_HOTX 7 #define WALK_DOWN_CURSOR_HOTY 31 -unsigned char paint_down_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFA, - 0x00, 0x00, 0x01, 0xF6, 0x00, 0x00, 0x03, 0xE4, 0x00, 0x03, 0x07, 0xCC, 0x00, 0x07, 0x84, 0x98, - 0x00, 0x0F, 0xC8, 0x70, 0x00, 0x1B, 0xF8, 0x60, 0x00, 0x3D, 0xE0, 0xC0, 0x00, 0x7E, 0xE3, 0x00, - 0x00, 0xFF, 0x62, 0x00, 0x00, 0xDF, 0xBE, 0x00, 0x00, 0x7F, 0xDF, 0x00, 0x00, 0x37, 0xEF, 0x80, - 0x00, 0x1B, 0xF7, 0xC0, 0x07, 0xCF, 0xFB, 0xC0, 0x04, 0x46, 0x9D, 0xC0, 0x04, 0x43, 0x07, 0x80, - 0x04, 0x41, 0x83, 0x00, 0x04, 0x40, 0xC6, 0x00, 0x04, 0x40, 0x6C, 0x00, 0x04, 0x40, 0x28, 0x00, - 0x7C, 0x7C, 0x10, 0x00, 0x20, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, - 0x04, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -unsigned char paint_down_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, - 0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x03, 0x07, 0xFC, 0x00, 0x07, 0x87, 0xF8, - 0x00, 0x0F, 0xCF, 0xF0, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, - 0x00, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0x80, - 0x00, 0x1F, 0xFF, 0xC0, 0x07, 0xCF, 0xFF, 0xC0, 0x07, 0xC7, 0xFF, 0xC0, 0x07, 0xC3, 0xFF, 0x80, - 0x07, 0xC1, 0xFF, 0x00, 0x07, 0xC0, 0xFE, 0x00, 0x07, 0xC0, 0x7C, 0x00, 0x07, 0xC0, 0x38, 0x00, - 0x7F, 0xFC, 0x10, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, - 0x07, 0xC0, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; +extern unsigned char paint_down_cursor_data[32 * 4]; +extern unsigned char paint_down_cursor_mask[32 * 4]; #define PAINT_DOWN_CURSOR_HOTX 8 #define PAINT_DOWN_CURSOR_HOTY 30 -unsigned char entrance_down_cursor_data[32 * 4] = { - 0x20, 0x00, 0x00, 0x08, 0x50, 0x00, 0x00, 0x14, 0x88, 0x00, 0x00, 0x22, 0x50, 0x00, 0x00, 0x14, - 0x7F, 0xFF, 0xFF, 0xFC, 0x58, 0x00, 0x00, 0x34, 0x54, 0x00, 0x00, 0x54, 0x54, 0x00, 0x00, 0x54, - 0x54, 0x00, 0x00, 0x54, 0x5C, 0x00, 0x00, 0x34, 0x5F, 0xFF, 0xFF, 0xF4, 0x50, 0x00, 0x00, 0x14, - 0x50, 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x14, - 0x50, 0x00, 0x00, 0x14, 0x5F, 0x80, 0x00, 0x14, 0xD8, 0x80, 0x00, 0x14, 0x58, 0x80, 0x02, 0xB5, - 0x58, 0x80, 0x00, 0x14, 0xD8, 0x80, 0x00, 0x14, 0x58, 0x80, 0x05, 0x74, 0x08, 0x80, 0x00, 0x00, - 0x08, 0x80, 0x00, 0xD2, 0xF8, 0xF8, 0x0E, 0x00, 0x40, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, - 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; -unsigned char entrance_down_cursor_mask[32 * 4] = { - 0x20, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x1C, 0xF8, 0x00, 0x00, 0x3E, 0x70, 0x00, 0x00, 0x1C, - 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x77, 0xFF, 0xFF, 0xDC, 0x77, 0xFF, 0xFF, 0xDC, - 0x77, 0xFF, 0xFF, 0xDC, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x70, 0x00, 0x00, 0x1C, - 0x70, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x1C, 0x70, 0x00, 0x00, 0x1C, - 0x70, 0x00, 0x00, 0x1C, 0x7F, 0x80, 0x00, 0x1C, 0xFF, 0x80, 0x00, 0x1C, 0x7F, 0x80, 0x02, 0xBD, - 0x7F, 0x80, 0x00, 0x1C, 0xFF, 0x80, 0x00, 0x1C, 0x7F, 0x80, 0x05, 0x7C, 0x0F, 0x80, 0x00, 0x00, - 0x0F, 0x80, 0x00, 0xD2, 0xFF, 0xF8, 0x0E, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -}; +extern unsigned char entrance_down_cursor_data[32 * 4]; +extern unsigned char entrance_down_cursor_mask[32 * 4]; #define ENTRANCE_DOWN_CURSOR_HOTX 7 #define ENTRANCE_DOWN_CURSOR_HOTY 31 -unsigned char hand_open_cursor_data[32 * 4] = { - 0x00, 0x06, 0x10, 0x00, 0x00, 0x09, 0x38, 0x00, 0x00, 0x09, 0x24, 0x00, 0x03, 0x08, 0xA4, 0x00, - 0x04, 0x88, 0xA4, 0xC0, 0x04, 0x48, 0x63, 0x20, 0x04, 0x24, 0x63, 0x10, 0x06, 0x24, 0x61, 0x90, - 0x02, 0x14, 0x21, 0x90, 0x03, 0x0C, 0x21, 0x10, 0x01, 0x04, 0x21, 0x10, 0x01, 0x86, 0x01, 0x10, - 0x00, 0x82, 0x00, 0x08, 0x00, 0xC0, 0x00, 0x08, 0x00, 0x60, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, - 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, - 0x0F, 0xC0, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x08, - 0x0F, 0x0F, 0x00, 0x04, 0x01, 0xF9, 0x80, 0x04, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00, 0x7F, 0xE0, -}; -unsigned char hand_open_cursor_mask[32 * 4] = { - 0x00, 0x06, 0x10, 0x00, 0x00, 0x0F, 0x38, 0x00, 0x00, 0x0F, 0x3C, 0x00, 0x03, 0x0F, 0xBC, 0x00, - 0x07, 0x8F, 0xBC, 0xC0, 0x07, 0xCF, 0xFF, 0xE0, 0x07, 0xE7, 0xFF, 0xF0, 0x07, 0xE7, 0xFF, 0xF0, - 0x03, 0xF7, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xF0, - 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, - 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF0, - 0x0F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xF8, - 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0xF9, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xE0, -}; +extern unsigned char hand_open_cursor_data[32 * 4]; +extern unsigned char hand_open_cursor_mask[32 * 4]; #define HAND_OPEN_CURSOR_HOTX 0 #define HAND_OPEN_CURSOR_HOTY 0 -unsigned char hand_closed_cursor_data[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xE0, 0x00, 0x00, 0x43, 0x10, 0x00, 0x00, 0x41, 0x8C, 0x00, - 0x00, 0x20, 0x87, 0x00, 0x0E, 0x20, 0x42, 0x80, 0x11, 0x98, 0x62, 0x40, 0x10, 0x6C, 0x61, 0x20, - 0x18, 0x14, 0x21, 0x20, 0x0C, 0x0C, 0x21, 0x10, 0x06, 0x04, 0x21, 0x10, 0x03, 0x06, 0x01, 0x10, - 0x00, 0x82, 0x00, 0x08, 0x00, 0xC0, 0x00, 0x08, 0x00, 0x60, 0x00, 0x08, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, - 0x07, 0x10, 0x00, 0x10, 0x08, 0x90, 0x00, 0x10, 0x08, 0x60, 0x00, 0x10, 0x0A, 0x00, 0x00, 0x10, - 0x0A, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x03, 0x80, 0x00, 0x08, - 0x00, 0x7F, 0x00, 0x04, 0x00, 0x01, 0x80, 0x04, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00, 0x7F, 0xE0, -}; -unsigned char hand_closed_cursor_mask[32 * 4] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xE0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x7F, 0xFC, 0x00, - 0x00, 0x3F, 0xFF, 0x00, 0x0E, 0x3F, 0xFF, 0x80, 0x1F, 0x9F, 0xFF, 0xC0, 0x1F, 0xEF, 0xFF, 0xE0, - 0x1F, 0xF7, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0, - 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, - 0x07, 0x1F, 0xFF, 0xF0, 0x0F, 0x9F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, - 0x0F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF8, - 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xE0, -}; +extern unsigned char hand_closed_cursor_data[32 * 4]; +extern unsigned char hand_closed_cursor_mask[32 * 4]; #define HAND_CLOSED_CURSOR_HOTX 0 #define HAND_CLOSED_CURSOR_HOTY 0 diff --git a/src/diagnostic.c b/src/diagnostic.c index 95c5661356..d2d06d5f7d 100644 --- a/src/diagnostic.c +++ b/src/diagnostic.c @@ -23,14 +23,15 @@ #include #include "diagnostic.h" -int _log_levels[DIAGNOSTIC_LEVEL_COUNT] = { 1, 1, 1, 0 }; +int _log_levels[DIAGNOSTIC_LEVEL_COUNT] = { 1, 1, 1, 0, 1 }; int _log_location_enabled = 1; const char * _level_strings[] = { "FATAL", "ERROR", "WARNING", - "VERBOSE" + "VERBOSE", + "INFO" }; void diagnostic_log(int diagnosticLevel, const char *format, ...) diff --git a/src/diagnostic.h b/src/diagnostic.h index 749618847c..21029db312 100644 --- a/src/diagnostic.h +++ b/src/diagnostic.h @@ -26,6 +26,7 @@ enum { DIAGNOSTIC_LEVEL_ERROR, DIAGNOSTIC_LEVEL_WARNING, DIAGNOSTIC_LEVEL_VERBOSE, + DIAGNOSTIC_LEVEL_INFORMATION, DIAGNOSTIC_LEVEL_COUNT }; @@ -42,6 +43,7 @@ void diagnostic_log_with_location(int diagnosticLevel, const char *file, const c #define log_error(format, ...) diagnostic_log_macro(DIAGNOSTIC_LEVEL_ERROR, format, __VA_ARGS__) #define log_warning(format, ...) diagnostic_log_macro(DIAGNOSTIC_LEVEL_WARNING, format, __VA_ARGS__) #define log_verbose(format, ...) diagnostic_log(DIAGNOSTIC_LEVEL_VERBOSE, format, __VA_ARGS__) +#define log_info(format, ...) diagnostic_log_macro(DIAGNOSTIC_LEVEL_INFORMATION, format, __VA_ARGS__) #else @@ -51,6 +53,7 @@ void diagnostic_log_with_location(int diagnosticLevel, const char *file, const c #define log_error(format, ...) diagnostic_log_macro(DIAGNOSTIC_LEVEL_ERROR, format, ## __VA_ARGS__) #define log_warning(format, ...) diagnostic_log_macro(DIAGNOSTIC_LEVEL_WARNING, format, ## __VA_ARGS__) #define log_verbose(format, ...) diagnostic_log(DIAGNOSTIC_LEVEL_VERBOSE, format, ## __VA_ARGS__) +#define log_info(format, ...) diagnostic_log_macro(DIAGNOSTIC_LEVEL_INFORMATION, format, ## __VA_ARGS__) #endif diff --git a/src/drawing/drawing.c b/src/drawing/drawing.c index 9dceb89a9a..b26c79ad60 100644 --- a/src/drawing/drawing.c +++ b/src/drawing/drawing.c @@ -22,7 +22,9 @@ #include "../common.h" #include "../localisation/localisation.h" #include "../interface/window.h" -#include "../platform/osinterface.h" +#include "../platform/platform.h" +#include "../object.h" +#include "../world/water.h" #include "drawing.h" // HACK These were originally passed back through registers @@ -31,7 +33,7 @@ int gLastDrawStringY; uint8 _screenDirtyBlocks[5120]; -#define MAX_RAIN_PIXELS 0x9000 +#define MAX_RAIN_PIXELS 0xFFFE uint32 rainPixels[MAX_RAIN_PIXELS]; //Originally 0x9ABE0C, 12 elements from 0xF3 are the peep top colour, 12 elements from 0xCA are peep trouser colour @@ -133,10 +135,10 @@ void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour) */ void gfx_transpose_palette(int pal, unsigned char product) { - rct_g1_element g1 = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[pal]; + rct_g1_element g1 = g1Elements[pal]; int width = g1.width; int x = g1.x_offset; - uint8* dest_pointer = (uint8*)&(RCT2_ADDRESS(0x014124680,uint8)[x]); + uint8* dest_pointer = (uint8*)&(RCT2_ADDRESS(0x01424680, uint8)[x * 4]); uint8* source_pointer = g1.offset; for (; width > 0; width--) { @@ -146,7 +148,33 @@ void gfx_transpose_palette(int pal, unsigned char product) source_pointer += 3; dest_pointer += 4; } - osinterface_update_palette((char*)0x01424680, 10, 236);//Odd would have expected dest_pointer + platform_update_palette((char*)0x01424680, 10, 236); +} + +/* rct2: 0x006837E3 */ +void load_palette(){ + rct_water_type* water_type = (rct_water_type*)object_entry_groups[OBJECT_TYPE_WATER].chunks[0]; + + uint32 palette = 0x5FC; + + if ((sint32)water_type != -1){ + palette = water_type->image_id; + } + + rct_g1_element g1 = g1Elements[palette]; + int width = g1.width; + int x = g1.x_offset; + uint8* dest_pointer = (uint8*)&(RCT2_ADDRESS(0x01424680, uint8)[x * 4]); + uint8* source_pointer = g1.offset; + + for (; width > 0; width--) { + dest_pointer[0] = source_pointer[0]; + dest_pointer[1] = source_pointer[1]; + dest_pointer[2] = source_pointer[2]; + source_pointer += 3; + dest_pointer += 4; + } + platform_update_palette((char*)0x01424680, 10, 236); } /** @@ -157,7 +185,7 @@ void gfx_transpose_palette(int pal, unsigned char product) * @param base_height (di) * @param clearance_height (si) */ -void gfx_invalidate_scrollingtext(int x, int y, int base_height, int clearance_height) +void gfx_invalidate_tile_if_zoomed(int x, int y, int base_height, int clearance_height) { x += 16; y += 16; @@ -486,7 +514,7 @@ void redraw_peep_and_rain() if (sprite != -1) { sprite = sprite & 0x7FFFF; - rct_g1_element *g1_elements = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[sprite]; + rct_g1_element *g1_elements = &g1Elements[sprite]; int left = RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, sint16) + g1_elements->x_offset; int top = RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, sint16) + g1_elements->y_offset; int right = left + g1_elements->width; @@ -518,4 +546,4 @@ void redraw_peep_and_rain() } } RCT2_GLOBAL(RCT2_ADDRESS_NO_RAIN_PIXELS, uint32) = 0; -} +} \ No newline at end of file diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index ab22bc8f7e..80f3713e1a 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -31,8 +31,7 @@ typedef struct { short width; // 0x08 short height; // 0x0A short pitch; // 0x0C note: this is actually (pitch - width) - uint8 zoom_level; // 0x0E - char var_0F; // 0x0F + uint16 zoom_level; // 0x0E } rct_drawpixelinfo; // Size: 0x10 @@ -65,16 +64,19 @@ extern uint8 text_palette[]; extern int gLastDrawStringX; extern int gLastDrawStringY; +extern rct_g1_element *g1Elements; + // rct_drawpixelinfo* clip_drawpixelinfo(rct_drawpixelinfo* dpi, int left, int width, int top, int height); void gfx_set_dirty_blocks(int left, int top, int right, int bottom); void gfx_draw_all_dirty_blocks(); void gfx_redraw_screen_rect(short left, short top, short right, short bottom); -void gfx_invalidate_scrollingtext(int x, int y, int base_height, int clearance_height); +void gfx_invalidate_tile_if_zoomed(int x, int y, int base_height, int clearance_height); void gfx_invalidate_screen(); // palette void gfx_transpose_palette(int pal, unsigned char product); +void load_palette(); // other void gfx_draw_rain(int left, int top, int width, int height, sint32 x_start, sint32 y_start); @@ -90,6 +92,8 @@ void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short ri // sprite int gfx_load_g1(); +int gfx_load_g2(); +void sub_68371D(); void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, int height, int width, int image_type); void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_pointer, uint8* palette_pointer, rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width); void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour); diff --git a/src/drawing/rect.c b/src/drawing/rect.c index c23f881b56..297dafd849 100644 --- a/src/drawing/rect.c +++ b/src/drawing/rect.c @@ -51,9 +51,9 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot uint16 cross_pattern = 0; int start_x = left - dpi->x; - if (start_x < 0){ - start_x = 0; + if (start_x < 0){ cross_pattern ^= start_x; + start_x = 0; } int end_x = right - dpi->x; @@ -64,9 +64,9 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot int width = end_x - start_x; int start_y = top - dpi->y; - if (start_y < 0){ - start_y = 0; + if (start_y < 0){ cross_pattern ^= start_y; + start_y = 0; } int end_y = bottom - dpi->y; end_y++; @@ -109,12 +109,12 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot // Find colour in colour table? uint16 eax = palette_to_g1_offset[(colour & 0xFF)]; - rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]; + rct_g1_element g1_element = g1Elements[eax]; // Fill the rectangle with the colours from the colour table for (int i = 0; i < height>>dpi->zoom_level; ++i) { uint8* next_dest_pointer = dest_pointer + (dpi->width >> dpi->zoom_level) + dpi->pitch; - for (int j = 0; j < width; ++j) { + for (int j = 0; j < width>>dpi->zoom_level; ++j) { *dest_pointer = g1_element.offset[*dest_pointer]; dest_pointer++; } @@ -160,7 +160,6 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot if (colour & 0x8000000){ //0x8000000 // 00678B3A 00678EC9 still to be implemented - //RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, dpi, colour); int esi = left - RCT2_GLOBAL(0x1420070,sint16); RCT2_GLOBAL(0xEDF824,uint32) = esi; esi = top - RCT2_GLOBAL(0x1420072,sint16); @@ -211,7 +210,7 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot esi = RCT2_GLOBAL(0xEDF828,sint32); esi *= 0x40; left = 0; - esi += (uint32)(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS,rct_g1_element)[right]).offset;//??? + esi += (uint32)g1Elements[right].offset;//??? //Not finished //Start of loop return; @@ -223,7 +222,6 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot memset(dest_pointer, (colour & 0xFF), width); dest_pointer += dpi->width + dpi->pitch; } - // RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, dpi, colour); } /** diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 0e28e76f7d..024675facd 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -20,7 +20,10 @@ #include "../addresses.h" #include "../common.h" +#include "../sprites.h" #include "drawing.h" +#include "../platform/platform.h" +#include "../openrct2.h" typedef struct { uint32 num_entries; @@ -29,6 +32,16 @@ typedef struct { void *_g1Buffer = NULL; +typedef struct { + rct_g1_header header; + rct_g1_element *elements; + void *data; +} rct_gx; + +rct_gx g2; + +rct_g1_element *g1Elements = (rct_g1_element*)RCT2_ADDRESS_G1_ELEMENTS; + /** * * rct2: 0x00678998 @@ -41,8 +54,6 @@ int gfx_load_g1() rct_g1_header header; unsigned int i; - rct_g1_element *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); - file = fopen(get_file_path(PATH_ID_G1), "rb"); if (file != NULL) { if (fread(&header, 8, 1, file) == 1) { @@ -74,13 +85,63 @@ int gfx_load_g1() return 0; } +int gfx_load_g2() +{ + log_verbose("loading g2 graphics"); + + FILE *file; + unsigned int i; + + char path[MAX_PATH]; + sprintf(path, "%s%cdata%cg2.dat", gExePath, platform_get_path_separator(), platform_get_path_separator()); + file = fopen(path, "rb"); + if (file != NULL) { + if (fread(&g2.header, 8, 1, file) == 1) { + // Read element headers + g2.elements = malloc(g2.header.num_entries * sizeof(rct_g1_element)); + fread(g2.elements, g2.header.num_entries * sizeof(rct_g1_element), 1, file); + + // Read element data + g2.data = malloc(g2.header.total_size); + fread(g2.data, g2.header.total_size, 1, file); + + fclose(file); + + // Fix entry data offsets + for (i = 0; i < g2.header.num_entries; i++) + g2.elements[i].offset += (int)g2.data; + + // Successful + return 1; + } + fclose(file); + } + + // Unsuccessful + log_fatal("Unable to load g2 graphics"); + return 0; +} + +/** + * This function looks like it initialises the 0x009E3CE4 array which references sprites used for background / palette mixing or + * something. Further investigation is needed. + */ +void sub_68371D() +{ + uint8 **unk_9E3CE4 = (uint8**)0x009E3CE4; + + unk_9E3CE4[0] = NULL; + for (int i = 1; i < 8; i++) + unk_9E3CE4[i] = g1Elements[23199 + i].offset; +} + /** * Copies a sprite onto the buffer. There is no compression used on the sprite * image. * rct2: 0x0067A690 */ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, int height, int width, int image_type){ - uint8 zoom_level = dest_dpi->zoom_level; + uint16 zoom_level = dest_dpi->zoom_level; uint8 zoom_amount = 1 << zoom_level; //Requires use of palette? if (image_type & IMAGE_TYPE_USE_PALETTE){ @@ -211,9 +272,16 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_pointer, uint8* palette_pointer, rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width){ int zoom_level = dpi->zoom_level; int zoom_amount = 1 << zoom_level; + int zoom_mask = 0xFFFFFFFF << zoom_level; uint8* next_source_pointer; uint8* next_dest_pointer = dest_bits_pointer; + if (source_y_start < 0){ + source_y_start += zoom_amount; + next_dest_pointer += dpi->width / zoom_amount + dpi->pitch; + height -= zoom_amount; + } + //For every line in the image for (int y = source_y_start; y < (height + source_y_start); y += zoom_amount){ @@ -242,6 +310,13 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point //Calculates the start point of the image int x_start = gap_size - source_x_start; + if (x_start & ~zoom_mask){ + no_pixels -= (x_start&~zoom_mask); + x_start += ~zoom_mask; + source_pointer += (x_start&~zoom_mask); + if (no_pixels <= 0) continue; + } + if (x_start > 0){ //Since the start is positive //We need to move the drawing surface to the correct position @@ -323,9 +398,6 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point */ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour) { - //RCT2_CALLPROC_X(0x0067A28E, 0, image_id, x, y, 0, (int)dpi, tertiary_colour); - //return; - int image_type = (image_id & 0xE0000000) >> 28; int image_sub_type = (image_id & 0x1C000000) >> 26; @@ -347,7 +419,7 @@ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 } uint16 palette_offset = palette_to_g1_offset[palette_ref]; - palette_pointer = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[palette_offset].offset; + palette_pointer = g1Elements[palette_offset].offset; } else if (image_type && !(image_type & IMAGE_TYPE_USE_PALETTE)){ RCT2_GLOBAL(0x9E3CDC, uint32) = 0; @@ -358,9 +430,9 @@ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 uint32 secondary_offset = palette_to_g1_offset[(image_id >> 24) & 0x1F]; uint32 tertiary_offset = palette_to_g1_offset[tertiary_colour]; - rct_g1_element* primary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[primary_offset]; - rct_g1_element* secondary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[secondary_offset]; - rct_g1_element* tertiary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[tertiary_offset]; + rct_g1_element* primary_colour = &g1Elements[primary_offset]; + rct_g1_element* secondary_colour = &g1Elements[secondary_offset]; + rct_g1_element* tertiary_colour = &g1Elements[tertiary_offset]; memcpy(palette_pointer + 0xF3, &primary_colour->offset[0xF3], 12); memcpy(palette_pointer + 0xCA, &secondary_colour->offset[0xF3], 12); @@ -379,13 +451,13 @@ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 //Top int top_type = (image_id >> 19) & 0x1f; uint32 top_offset = palette_to_g1_offset[top_type]; //RCT2_ADDRESS(0x97FCBC, uint32)[top_type]; - rct_g1_element top_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[top_offset]; + rct_g1_element top_palette = g1Elements[top_offset]; memcpy(palette_pointer + 0xF3, top_palette.offset + 0xF3, 12); //Trousers int trouser_type = (image_id >> 24) & 0x1f; uint32 trouser_offset = palette_to_g1_offset[trouser_type]; //RCT2_ADDRESS(0x97FCBC, uint32)[trouser_type]; - rct_g1_element trouser_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[trouser_offset]; + rct_g1_element trouser_palette = g1Elements[trouser_offset]; memcpy(palette_pointer + 0xCA, trouser_palette.offset + 0xF3, 12); } @@ -404,26 +476,18 @@ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 * x (cx) * y (dx) */ -void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer){ - int image_element = 0x7FFFF&image_id; +void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer) +{ + int image_element = image_id & 0x7FFFF; int image_type = (image_id & 0xE0000000) >> 28; - rct_g1_element* g1_source = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[image_element]); + rct_g1_element* g1_source; + if (image_element < SPR_G2_BEGIN) { + g1_source = &g1Elements[image_element]; + } else { + g1_source = &g2.elements[image_element - SPR_G2_BEGIN]; + } - //Zooming code has been integrated into main code. - //if (dpi->zoom_level >= 1){ //These have not been tested - // //something to do with zooming - // if (dpi->zoom_level == 1){ - // RCT2_CALLPROC_X(0x0067A28E, 0, image_id, x, y, 0, (int)dpi, 0); - // return; - // } - // if (dpi->zoom_level == 2){ - // RCT2_CALLPROC_X(0x0067DADA, 0, (int)g1_source, x, y, 0, (int)dpi, 0); - // return; - // } - // RCT2_CALLPROC_X(0x0067FAAE, 0, (int)g1_source, x, y, 0, (int)dpi, 0); - // return; - //} if ( dpi->zoom_level && (g1_source->flags & (1<<4)) ){ rct_drawpixelinfo zoomed_dpi = { .bits = dpi->bits, @@ -447,10 +511,24 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in int zoom_amount = 1 << zoom_level; int zoom_mask = 0xFFFFFFFF << zoom_level; + if (zoom_level && g1_source->flags & G1_FLAG_RLE_COMPRESSION){ + x -= ~zoom_mask; + y -= ~zoom_mask; + } + //This will be the height of the drawn image int height = g1_source->height; //This is the start y coordinate on the destination - sint16 dest_start_y = ((y + g1_source->y_offset)&zoom_mask) - dpi->y; + sint16 dest_start_y = y + g1_source->y_offset; + + // For whatever reason the RLE version does not use + // the zoom mask on the y coordinate but does on x. + if (g1_source->flags & G1_FLAG_RLE_COMPRESSION){ + dest_start_y -= dpi->y; + } + else{ + dest_start_y = (dest_start_y&zoom_mask) - dpi->y; + } //This is the start y coordinate on the source int source_start_y = 0; @@ -467,6 +545,12 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in //The destination start is now reset to 0 dest_start_y = 0; } + else{ + if (g1_source->flags & G1_FLAG_RLE_COMPRESSION && zoom_level){ + source_start_y -= dest_start_y & ~zoom_mask; + height += dest_start_y & ~zoom_mask; + } + } int dest_end_y = dest_start_y + height; @@ -486,7 +570,7 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in //This is the source start x coordinate int source_start_x = 0; //This is the destination start x coordinate - sint16 dest_start_x = ((x + g1_source->x_offset) & zoom_mask) - dpi->x; + sint16 dest_start_x = ((x + g1_source->x_offset + ~zoom_mask)&zoom_mask) - dpi->x; if (dest_start_x < 0){ //If the destination is negative reduce the width @@ -501,6 +585,11 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in //Reset the destination to 0 dest_start_x = 0; } + else{ + if (g1_source->flags & G1_FLAG_RLE_COMPRESSION && zoom_level){ + source_start_x -= dest_start_x & ~zoom_mask; + } + } int dest_end_x = dest_start_x + width; @@ -554,7 +643,7 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in ecx >>= 3;//SAR int eax = ((int)no_pixels)<<8; ecx = -ecx;//Odd - eax = eax & 0xFF00 + *(source_pointer+1); + eax = (eax & 0xFF00) + *(source_pointer+1); total_no_pixels -= ecx; source_pointer += 2; ebx = (uint32)new_source_pointer - eax; diff --git a/src/drawing/string.c b/src/drawing/string.c index 8080ae8afd..3acb688e86 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -32,7 +32,7 @@ void gfx_load_character_widths(){ uint8* char_width_pointer = RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8); for (int char_set_offset = 0; char_set_offset < 4*0xE0; char_set_offset+=0xE0){ for (uint8 c = 0; c < 0xE0; c++, char_width_pointer++){ - rct_g1_element g1 = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[c + SPR_CHAR_START + char_set_offset]; + rct_g1_element g1 = g1Elements[c + SPR_CHAR_START + char_set_offset]; int width; if (char_set_offset == 0xE0*3) width = g1.width + 1; @@ -75,7 +75,7 @@ void gfx_load_character_widths(){ } for (int i = 0; i < 0x20; ++i){ - rct_g1_element* g1 = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[0x606 + i]); + rct_g1_element* g1 = &g1Elements[0x606 + i]; uint8* unknown_pointer = RCT2_ADDRESS(0x9C3852, uint8) + 0xa12 * i; g1->offset = unknown_pointer; g1->width = 0x40; @@ -138,7 +138,7 @@ int gfx_get_string_width_new_lined(char* buffer){ case 0x10: continue; case FORMAT_INLINE_SPRITE: - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char + 1)) & 0x7FFFF]; + g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; width += g1_element.width; curr_char += 4; break; @@ -214,7 +214,7 @@ int gfx_get_string_width(char* buffer) case 0x10: continue; case FORMAT_INLINE_SPRITE: - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char+1))&0x7FFFF]; + g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; width += g1_element.width; curr_char += 4; break; @@ -297,7 +297,7 @@ int gfx_clip_string(char* buffer, int width) case 0x10: continue; case FORMAT_INLINE_SPRITE: - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char+1))&0x7FFFF]; + g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; clipped_width += g1_element.width; curr_char += 4; continue; @@ -396,7 +396,7 @@ int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height) case 0x10: continue; case FORMAT_INLINE_SPRITE: - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char + 1)) & 0x7FFFF]; + g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; line_width += g1_element.width; curr_char += 4; break; @@ -718,7 +718,7 @@ void colour_char(uint8 colour, uint16* current_font_flags, uint8* palette_pointe int eax; - rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[0x1332]; + rct_g1_element g1_element = g1Elements[0x1332]; eax = ((uint32*)g1_element.offset)[colour & 0xFF]; if (!(*current_font_flags & 2)) { @@ -773,8 +773,8 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in int max_y = y; // - uint16* current_font_flags = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); - uint16* current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + uint16 *current_font_flags = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + sint16 *current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16); uint8* palette_pointer = text_palette; @@ -802,10 +802,10 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in *current_font_flags = 0; if (*current_font_sprite_base < 0) { *current_font_flags |= 4; - if (*current_font_sprite_base != 0xFFFF) { + if (*current_font_sprite_base != -1) { *current_font_flags |= 8; } - *current_font_sprite_base = 0xE0; + *current_font_sprite_base = 224; } if (colour & (1 << 5)) { *current_font_flags |= 2; @@ -896,7 +896,7 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in } eax = palette_to_g1_offset[al]; //RCT2_ADDRESS(0x097FCBC, uint32)[al * 4]; - g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); + g1_element = &g1Elements[eax]; ebx = g1_element->offset[0xF9] + (1 << 8); if (!(*current_font_flags & 2)) { ebx = ebx & 0xFF; @@ -917,11 +917,11 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in break; case FORMAT_NEWLINE://Start New Line at set y lower max_x = x; - if (*current_font_sprite_base <= 0xE0) { + if (*current_font_sprite_base <= 224) { max_y += 10; break; } - else if (*current_font_sprite_base == 0x1C0) { + else if (*current_font_sprite_base == 448) { max_y += 6; break; } @@ -929,24 +929,24 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in break; case FORMAT_NEWLINE_SMALLER://Start New Line at set y lower max_x = x; - if (*current_font_sprite_base <= 0xE0) { + if (*current_font_sprite_base <= 224) { max_y += 5; break; } - else if (*current_font_sprite_base == 0x1C0) { + else if (*current_font_sprite_base == 448) { max_y += 3; break; } max_y += 9; break; case FORMAT_TINYFONT: - *current_font_sprite_base = 0x1C0; + *current_font_sprite_base = 448; break; case FORMAT_BIGFONT: - *current_font_sprite_base = 0x2A0; + *current_font_sprite_base = 672; break; case FORMAT_MEDIUMFONT: - *current_font_sprite_base = 0xE0; + *current_font_sprite_base = 224; break; case FORMAT_SMALLFONT: *current_font_sprite_base = 0; @@ -1006,11 +1006,11 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in skip_char = 1; break; } - ebx = *((uint16*)(buffer - 3)); - eax = ebx & 0x7FFFF; - g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); + uint32 image_id = *((uint32*)(buffer - 3)); + uint32 image_offset = image_id & 0x7FFFF; + g1_element = &g1Elements[image_offset]; - gfx_draw_sprite(dpi, ebx, max_x, max_y, 0); + gfx_draw_sprite(dpi, image_id, max_x, max_y, 0); max_x = max_x + g1_element->width; break; @@ -1044,7 +1044,7 @@ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, in uint32 char_offset = al - 0x20 + *current_font_sprite_base; RCT2_GLOBAL(0x00EDF81C, uint32) = (IMAGE_TYPE_USE_PALETTE << 28); - gfx_draw_sprite_palette_set(dpi, (IMAGE_TYPE_USE_PALETTE << 28) | char_offset + SPR_CHAR_START, max_x, max_y, palette_pointer, NULL); + gfx_draw_sprite_palette_set(dpi, ((IMAGE_TYPE_USE_PALETTE << 28) | char_offset) + SPR_CHAR_START, max_x, max_y, palette_pointer, NULL); max_x += (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[char_offset] & 0xFF); continue; } @@ -1110,5 +1110,35 @@ void draw_string_centred_underline(rct_drawpixelinfo *dpi, int format, void *arg */ void draw_string_centred_raw(rct_drawpixelinfo *dpi, int x, int y, int numLines, char *text) { - RCT2_CALLPROC_X(0x006C1DB7, 0, 0, x, y, (int)text, (int)dpi, numLines); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + gfx_draw_string(dpi, (char*)0x009C383D, 0, dpi->x, dpi->y); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + for (int i = 0; i <= numLines; i++) { + int width = gfx_get_string_width(text); + gfx_draw_string(dpi, text, 254, x - (width / 2), y); + + char c; + while ((c = *text++) != 0) { + if (c >= 32) continue; + if (c <= 4) { + text++; + continue; + } + if (c <= 16) continue; + text += 2; + if (c <= 22) continue; + text += 2; + } + + y += 10; + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) <= 224) + continue; + + y -= 4; + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) <= 448) + continue; + + y += 12; + } } \ No newline at end of file diff --git a/src/editor.c b/src/editor.c index 23274db7fd..58e25e0cbf 100644 --- a/src/editor.c +++ b/src/editor.c @@ -31,7 +31,8 @@ #include "management/news_item.h" #include "object.h" #include "peep/staff.h" -#include "platform/osinterface.h" +#include "platform/platform.h" +#include "rct1.h" #include "ride/ride.h" #include "scenario.h" #include "util/sawyercoding.h" @@ -40,14 +41,13 @@ #include "world/climate.h" #include "world/map.h" #include "world/park.h" +#include "world/scenery.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 void editor_finalise_main_view(); static int editor_read_s6(const char *path); /** @@ -61,8 +61,8 @@ void editor_load() pause_sounds(); unpause_sounds(); object_unload_all(); - map_init(); - RCT2_CALLPROC_EBPSAFE(0x006B9CB0); + map_init(150); + banner_init(); reset_park_entrances(); user_string_clear_all(); reset_sprite_list(); @@ -85,9 +85,11 @@ void editor_load() mainWindow = window_get_main(); window_scroll_to_location(mainWindow, 2400, 2400, 112); mainWindow->flags &= ~WF_SCROLLING_TO_LOCATION; - RCT2_CALLPROC_EBPSAFE(0x006837E3); + load_palette(); gfx_invalidate_screen(); RCT2_GLOBAL(0x009DEA66, sint16) = 0; + + strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, language_get_string(2749)); } /** @@ -106,7 +108,7 @@ static int show_convert_saved_game_to_scenario_dialog(char *resultPath) format_string(filterName, STR_RCT2_SAVED_GAME, NULL); pause_sounds(); - result = osinterface_open_common_file_dialog(1, title, filename, "*.SV6", filterName); + result = platform_open_common_file_dialog(1, title, filename, "*.SV6", filterName); unpause_sounds(); if (result) @@ -122,8 +124,6 @@ void editor_convert_save_to_scenario() { rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; char savedGamePath[MAX_PATH]; - rct_window *w; - rct_viewport *viewport; tool_cancel(); if (!show_convert_saved_game_to_scenario_dialog(savedGamePath)) @@ -149,9 +149,10 @@ void editor_convert_save_to_scenario() s6Info->objective_arg_3 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, sint16); climate_reset(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8)); - if (RCT2_GLOBAL(0x009ADAE4, uint32) != 0xFFFFFFFF) { - object_unload(0, (rct_object_entry_extended*)0x00F4287C); - RCT2_CALLPROC_EBPSAFE(0x006A9FC0); + rct_stex_entry* stex = g_stexEntries[0]; + if ((int)stex != 0xFFFFFFFF) { + object_unload(0, &object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); + reset_loaded_objects(); format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); s6Info->name[0] = 0; @@ -163,39 +164,7 @@ void editor_convert_save_to_scenario() viewport_init_all(); news_item_init_queue(); window_editor_main_open(); - - // Initialise main view - w = window_get_main(); - viewport = w->viewport; - - w->viewport_target_sprite = -1; - w->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16); - w->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16); - - viewport->zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) & 0xFF; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) >> 8; - - int cx = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) - viewport->zoom; - if (cx != 0) { - if (cx >= 0) { - viewport->view_width <<= cx; - viewport->view_height <<= cx; - } else { - cx = -cx; - viewport->view_width >>= cx; - viewport->view_height >>= cx; - } - } - w->saved_view_x -= viewport->view_width >> 1; - w->saved_view_y -= viewport->view_height >> 1; - - window_invalidate(w); - sub_69E9A7(); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); - window_new_ride_init_vars(); - RCT2_GLOBAL(0x009DEB7C, uint16) = 0; - RCT2_CALLPROC_EBPSAFE(0x006837E3); // (palette related) - gfx_invalidate_screen(); + editor_finalise_main_view(); RCT2_GLOBAL(0x009DEA66, uint16) = 0; } @@ -208,9 +177,9 @@ void trackdesigner_load() rct_window *mainWindow; object_unload_all(); - map_init(); + map_init(150); set_all_land_owned(); - RCT2_CALLPROC_EBPSAFE(0x006B9CB0); + banner_init(); reset_park_entrances(); user_string_clear_all(); reset_sprite_list(); @@ -231,7 +200,7 @@ void trackdesigner_load() mainWindow = window_get_main(); window_scroll_to_location(mainWindow, 2400, 2400, 112); mainWindow->flags &= ~WF_SCROLLING_TO_LOCATION; - RCT2_CALLPROC_EBPSAFE(0x006837E3); + load_palette(); gfx_invalidate_screen(); RCT2_GLOBAL(0x009DEA66, sint16) = 0; } @@ -245,9 +214,9 @@ void trackmanager_load() rct_window *mainWindow; object_unload_all(); - map_init(); + map_init(150); set_all_land_owned(); - RCT2_CALLPROC_EBPSAFE(0x006B9CB0); + banner_init(); reset_park_entrances(); user_string_clear_all(); reset_sprite_list(); @@ -268,7 +237,7 @@ void trackmanager_load() mainWindow = window_get_main(); window_scroll_to_location(mainWindow, 2400, 2400, 112); mainWindow->flags &= ~WF_SCROLLING_TO_LOCATION; - RCT2_CALLPROC_EBPSAFE(0x006837E3); + load_palette(); gfx_invalidate_screen(); RCT2_GLOBAL(0x009DEA66, sint16) = 0; } @@ -285,24 +254,18 @@ static void set_all_land_owned() } /** -* -* rct2: 0x006BD3A4 -*/ -void sub_6BD3A4() { - for (short i = 0; i < 200; i++) { - RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[i] = STAFF_MODE_NONE; - } - for (short i = 200; i < 204; i++) { - RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[i] = STAFF_MODE_WALK; - } - //RCT2_CALLPROC_EBPSAFE(0x006C0C3F); - sub_6C0C3F(); -} - -static void read(void *dst, void **src, int length) + * + * rct2: 0x006BD3A4 + */ +void sub_6BD3A4() { - memcpy(dst, *src, length); - *((char**)src) += length; + for (int i = 0; i < 200; i++) + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[i] = STAFF_MODE_NONE; + + for (int i = 200; i < 204; i++) + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[i] = STAFF_MODE_WALK; + + staff_update_greyed_patrol_areas(); } /** @@ -334,152 +297,37 @@ void editor_load_landscape(const char *path) */ static int editor_load_landscape_from_sv4(const char *path) { - FILE *fp; - long fpLength; - char *fpBuffer; + rct1_s4 *s4; - // Open file - fp = fopen(path, "rb"); - if (fp == NULL) { - RCT2_GLOBAL(0x009AC31B, uint8) = 255; - RCT2_GLOBAL(0x009AC31C, uint16) = 3011; + s4 = malloc(sizeof(rct1_s4)); + if (!rct1_read_sv4(path, s4)) { + free(s4); return 0; } + rct1_import_s4(s4); + free(s4); - // Read whole file into a buffer - fpLength = fsize(fp); - fpBuffer = malloc(fpLength); - fread(fpBuffer, fpLength, 1, fp); - fclose(fp); - - editor_read_sv4(fpBuffer, fpLength); - free(fpBuffer); - - RCT2_CALLPROC_EBPSAFE(0x006A2B62); + rct1_fix_landscape(); + editor_finalise_main_view(); + RCT2_GLOBAL(0x009DEA66, uint16) = 0; return 1; } static int editor_load_landscape_from_sc4(const char *path) { - FILE *fp; - long fpLength; - char *fpBuffer; + rct1_s4 *s4; - // Open file - fp = fopen(path, "rb"); - if (fp == NULL) { - RCT2_GLOBAL(0x009AC31B, uint8) = 255; - RCT2_GLOBAL(0x009AC31C, uint16) = 3011; + s4 = malloc(sizeof(rct1_s4)); + if (!rct1_read_sc4(path, s4)) { + free(s4); return 0; } + rct1_import_s4(s4); + free(s4); - // 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].type = 255; - - read((void*)0x013573BC, &src, 12424); - - for (i = 0; i < MAX_BANNERS; i++) { - banner = &gBanners[i]; - if (banner->type != 255 && banner->string_idx != 3458) - banner->string_idx = 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); + rct1_fix_landscape(); + editor_finalise_main_view(); + RCT2_GLOBAL(0x009DEA66, uint16) = 0; return 1; } @@ -494,17 +342,14 @@ static int editor_read_s6(const char *path) rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - // strcpy((char *)0x0141EF68, path); - // RCT2_CALLPROC_EBPSAFE(0x006758FE); - log_verbose("loading landscape, %s", path); file = fopen(path, "rb"); if (file != NULL) { if (!sawyercoding_validate_checksum(file)) { fclose(file); - RCT2_GLOBAL(0x009AC31B, uint8) = 255; - RCT2_GLOBAL(0x009AC31C, uint16) = STR_FILE_CONTAINS_INVALID_DATA; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; log_error("failed to load scenario, invalid checksum"); return 0; @@ -577,10 +422,8 @@ static int editor_read_s6(const char *path) set_load_objects_fail_reason(); return 0; } - // Check expansion pack - // RCT2_CALLPROC_EBPSAFE(0x006757E6); - RCT2_CALLPROC_EBPSAFE(0x006A9FC0); + reset_loaded_objects(); map_update_tile_pointers(); map_remove_all_rides(); @@ -609,8 +452,8 @@ static int editor_read_s6(const char *path) RCT2_GLOBAL(0x01357BC8, uint16) = 0; RCT2_GLOBAL(0x013573FE, uint16) = 0; if (s6Header->type != S6_TYPE_SCENARIO) { - RCT2_CALLPROC_EBPSAFE(0x00685675); - RCT2_CALLPROC_EBPSAFE(0x0068585B); + research_populate_list_random(); + research_remove_non_separate_vehicle_types(); if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY_SCENARIO; @@ -633,7 +476,7 @@ static int editor_read_s6(const char *path) RCT2_GLOBAL(0x013573DC, uint32) = min(RCT2_GLOBAL(0x013573DC, uint32), 100000); RCT2_CALLPROC_EBPSAFE(0x0069E89B); - RCT2_CALLPROC_EBPSAFE(0x0069E869); + sub_69E869(); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp( MONEY(0,00), @@ -641,9 +484,9 @@ static int editor_read_s6(const char *path) MONEY(5000000,00) ); - RCT2_GLOBAL(0x013580F0, money32) = clamp( + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = clamp( MONEY(0,00), - RCT2_GLOBAL(0x013580F0, money32), + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32), MONEY(5000000,00) ); @@ -656,9 +499,10 @@ static int editor_read_s6(const char *path) climate_reset(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8)); - if (RCT2_GLOBAL(0x009ADAE4, uint32) != 0xFFFFFFFF) { - object_unload(0, (rct_object_entry_extended*)0x00F4287C); - RCT2_CALLPROC_EBPSAFE(0x006A9FC0); + rct_stex_entry* stex = g_stexEntries[0]; + if ((int)stex != 0xFFFFFFFF) { + object_unload(0, &object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); + reset_loaded_objects(); format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); s6Info->name[0] = 0; @@ -668,46 +512,13 @@ static int editor_read_s6(const char *path) viewport_init_all(); news_item_init_queue(); window_editor_main_open(); - - // Initialise main view - rct_window *w = window_get_main(); - rct_viewport *viewport = w->viewport; - - w->viewport_target_sprite = -1; - w->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16); - w->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16); - - viewport->zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) & 0xFF; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) >> 8; - - int cx = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) - viewport->zoom; - if (cx != 0) { - if (cx >= 0) { - viewport->view_width <<= cx; - viewport->view_height <<= cx; - } else { - cx = -cx; - viewport->view_width >>= cx; - viewport->view_height >>= cx; - } - } - w->saved_view_x -= viewport->view_width >> 1; - w->saved_view_y -= viewport->view_height >> 1; - - window_invalidate(w); - sub_69E9A7(); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); - window_new_ride_init_vars(); - RCT2_GLOBAL(0x009DEB7C, uint16) = 0; - RCT2_CALLPROC_EBPSAFE(0x006837E3); // (palette related) - gfx_invalidate_screen(); - + editor_finalise_main_view(); return 1; } log_error("failed to find scenario file."); - RCT2_GLOBAL(0x009AC31B, uint8) = 255; - RCT2_GLOBAL(0x009AC31C, uint16) = STR_FILE_CONTAINS_INVALID_DATA; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; return 0; } @@ -728,7 +539,7 @@ void editor_open_windows_for_current_step() if (window_find_by_class(49)) return; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { object_unload_all(); } @@ -754,3 +565,38 @@ void editor_open_windows_for_current_step() break; } } + +static void editor_finalise_main_view() +{ + rct_window *w = window_get_main(); + rct_viewport *viewport = w->viewport; + + w->viewport_target_sprite = -1; + w->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16); + w->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16); + + viewport->zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) & 0xFF; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) >> 8; + + int zoom_difference = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) - viewport->zoom; + if (zoom_difference != 0) { + if (zoom_difference >= 0) { + viewport->view_width <<= zoom_difference; + viewport->view_height <<= zoom_difference; + } else { + zoom_difference = -zoom_difference; + viewport->view_width >>= zoom_difference; + viewport->view_height >>= zoom_difference; + } + } + w->saved_view_x -= viewport->view_width >> 1; + w->saved_view_y -= viewport->view_height >> 1; + + window_invalidate(w); + reset_all_sprite_quadrant_placements(); + scenery_set_default_placement_configuration(); + window_new_ride_init_vars(); + RCT2_GLOBAL(0x009DEB7C, uint16) = 0; + load_palette(); + gfx_invalidate_screen(); +} \ No newline at end of file diff --git a/src/game.c b/src/game.c index d30caa3185..1245676d68 100644 --- a/src/game.c +++ b/src/game.c @@ -23,6 +23,7 @@ #include "config.h" #include "game.h" #include "editor.h" +#include "world/footpath.h" #include "input.h" #include "localisation/localisation.h" #include "interface/screenshot.h" @@ -30,15 +31,18 @@ #include "interface/widget.h" #include "interface/window.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/peep.h" #include "peep/staff.h" -#include "platform/osinterface.h" +#include "platform/platform.h" #include "ride/ride.h" #include "ride/ride_ratings.h" #include "ride/vehicle.h" +#include "ride/track.h" #include "scenario.h" #include "title.h" #include "tutorial.h" @@ -47,19 +51,28 @@ #include "windows/error.h" #include "windows/tooltip.h" #include "world/climate.h" +#include "world/map_animation.h" #include "world/park.h" +#include "world/scenery.h" #include "world/sprite.h" +#include "world/water.h" int gGameSpeed = 1; void game_increase_game_speed() { - gGameSpeed = min(8, gGameSpeed + 1); + gGameSpeed = min(gConfigGeneral.debugging_tools ? 5 : 4, gGameSpeed + 1); + if (gGameSpeed == 5) + gGameSpeed = 8; + window_invalidate_by_class(WC_TOP_TOOLBAR); } void game_reduce_game_speed() { gGameSpeed = max(1, gGameSpeed - 1); + if (gGameSpeed == 7) + gGameSpeed = 4; + window_invalidate_by_class(WC_TOP_TOOLBAR); } /** @@ -69,9 +82,9 @@ void game_reduce_game_speed() void game_create_windows() { window_main_open(); - window_game_top_toolbar_open(); + window_top_toolbar_open(); window_game_bottom_toolbar_open(); - RCT2_CALLPROC_EBPSAFE(0x0066B905); + window_resize_gui(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)); } /** @@ -80,13 +93,16 @@ void game_create_windows() */ void update_palette_effects() { + rct_water_type* water_type = (rct_water_type*)object_entry_groups[OBJECT_TYPE_WATER].chunks[0]; + if (RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 1) { // change palette to lighter color during lightning int palette = 1532; - if (RCT2_GLOBAL(0x009ADAE0, sint32) != -1) { - palette = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 2, int); + + if ((sint32)water_type != -1) { + palette = water_type->image_id; } - rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[palette]; + rct_g1_element g1_element = g1Elements[palette]; int xoffset = g1_element.x_offset; xoffset = xoffset * 4; for (int i = 0; i < g1_element.width; i++) { @@ -95,17 +111,19 @@ void update_palette_effects() RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 2] = -((0xFF - g1_element.offset[(i * 3) + 2]) / 2) - 1; } RCT2_GLOBAL(0x014241BC, uint32) = 2; - osinterface_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); + platform_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); RCT2_GLOBAL(0x014241BC, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8)++; } else { if (RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 2) { // change palette back to normal after lightning int palette = 1532; - if (RCT2_GLOBAL(0x009ADAE0, sint32) != -1) { - palette = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 2, int); + + if ((sint32)water_type != -1) { + palette = water_type->image_id; } - rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[palette]; + + rct_g1_element g1_element = g1Elements[palette]; int xoffset = g1_element.x_offset; xoffset = xoffset * 4; for (int i = 0; i < g1_element.width; i++) { @@ -124,13 +142,13 @@ void update_palette_effects() q = 2; } } - uint32 j = RCT2_GLOBAL(0x009DE584, uint32); + uint32 j = RCT2_GLOBAL(RCT2_ADDRESS_PALETTE_EFFECT_FRAME_NO, uint32); j = (((uint16)((~j / 2) * 128) * 15) >> 16); int p = 1533; - if (RCT2_GLOBAL(0x009ADAE0, int) != -1) { - p = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 0x6, int); + if ((sint32)water_type != -1) { + p = water_type->var_06; } - rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[q + p]; + rct_g1_element g1_element = g1Elements[q + p]; uint8* vs = &g1_element.offset[j * 3]; uint8* vd = RCT2_ADDRESS(0x01424A18, uint8); int n = 5; @@ -146,10 +164,10 @@ void update_palette_effects() } p = 1536; - if (RCT2_GLOBAL(0x009ADAE0, int) != -1) { - p = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 0xA, int); + if ((sint32)water_type != -1) { + p = water_type->var_0A; } - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[q + p]; + g1_element = g1Elements[q + p]; vs = &g1_element.offset[j * 3]; n = 5; for (int i = 0; i < n; i++) { @@ -163,9 +181,9 @@ void update_palette_effects() vd += 4; } - j = ((uint16)(RCT2_GLOBAL(0x009DE584, uint32) * -960) * 3) >> 16; + j = ((uint16)(RCT2_GLOBAL(RCT2_ADDRESS_PALETTE_EFFECT_FRAME_NO, uint32) * -960) * 3) >> 16; p = 1539; - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[q + p]; + g1_element = g1Elements[q + p]; vs = &g1_element.offset[j * 3]; vd += 12; n = 3; @@ -181,11 +199,11 @@ void update_palette_effects() } RCT2_GLOBAL(0x014241BC, uint32) = 2; - osinterface_update_palette(RCT2_ADDRESS(0x01424680, uint8), 230, 16); + platform_update_palette(RCT2_ADDRESS(0x01424680, uint8), 230, 16); RCT2_GLOBAL(0x014241BC, uint32) = 0; if (RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 2) { RCT2_GLOBAL(0x014241BC, uint32) = 2; - osinterface_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); + platform_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); RCT2_GLOBAL(0x014241BC, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) = 0; } @@ -199,13 +217,12 @@ void update_palette_effects() void game_update() { - int i, numUpdates, tmp; + int i, numUpdates; // Handles picked-up peep and rain redraw redraw_peep_and_rain(); // 0x006E3AEC // screen_game_process_mouse_input(); - // RCT2_CALLPROC_EBPSAFE(0x006E3AEC); // screen_game_process_keyboard_input(); screenshot_check(); game_handle_keyboard_input(); @@ -218,7 +235,7 @@ void game_update() } // Update the game one or more times - if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) { for (i = 0; i < numUpdates; i++) { game_logic_update(); start_title_music(); @@ -234,7 +251,7 @@ void game_update() if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == INPUT_STATE_RESET || RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == INPUT_STATE_NORMAL ) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_VIEWPORT_SCROLLING) { RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_VIEWPORT_SCROLLING; break; } @@ -245,20 +262,30 @@ void game_update() } } + news_item_update_current(); + window_dispatch_update_all(); + RCT2_GLOBAL(0x009A8C28, uint8) = 0; RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_VIEWPORT_SCROLLING; - RCT2_GLOBAL(0x009AC861, uint16) ^= (1 << 15); - RCT2_GLOBAL(0x009AC861, uint16) &= ~(1 << 1); - tmp = RCT2_GLOBAL(0x009AC861, uint16) & (1 << 0); - RCT2_GLOBAL(0x009AC861, uint16) &= ~(1 << 0); - if (!tmp) - RCT2_GLOBAL(0x009AC861, uint16) |= (1 << 1); - RCT2_GLOBAL(0x009AC861, uint16) &= ~(1 << 3); - tmp = RCT2_GLOBAL(0x009AC861, uint16) & (1 << 2); - RCT2_GLOBAL(0x009AC861, uint16) &= ~(1 << 2); - if (!tmp) - RCT2_GLOBAL(0x009AC861, uint16) |= (1 << 2); + + // the flickering frequency is reduced by 4, compared to the original + // it was done due to inability to reproduce original frequency + // and decision that the original one looks too fast + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, sint32) % 4 == 0) + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) ^= (1 << 15); + + // Handle guest map flashing + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) &= ~(1 << 1); + if (RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) & (1 << 0)) + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 1); + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) &= ~(1 << 0); + + // Handle staff map flashing + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) &= ~(1 << 3); + if (RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) & (1 << 2)) + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 3); + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) &= ~(1 << 2); window_map_tooltip_update_visibility(); window_update_all(); @@ -272,17 +299,17 @@ void game_update() update_palette_effects(); update_rain_animation(); + stop_completed_sounds(); // removes other sounds that are no longer playing, this is normally called somewhere in rct2_init + if (RCT2_GLOBAL(0x009AAC73, uint8) != 255) { RCT2_GLOBAL(0x009AAC73, uint8)++; if (RCT2_GLOBAL(0x009AAC73, uint8) == 255) - config_save(); + config_save_default(); } } void game_logic_update() { - short stringId, _dx; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, sint32)++; RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, sint32)++; RCT2_GLOBAL(0x009DEA66, sint16)++; @@ -292,38 +319,35 @@ void game_logic_update() sub_68B089(); scenario_update(); climate_update(); - fountain_update_all(); + map_update_tiles(); sub_6A876D(); peep_update_all(); vehicle_update_all(); - texteffect_update_all(); + sprite_misc_update_all(); ride_update_all(); park_update(); research_update(); ride_ratings_update_all(); ride_measurements_update(); - map_invalidate_animations(); + map_animation_invalidate_all(); vehicle_sounds_update(); peep_update_crowd_noise(); climate_update_sound(); - news_item_update_current(); editor_open_windows_for_current_step(); - stop_completed_sounds(); // removes other sounds that are no longer playing, this is normally called somewhere in rct2_init - // Update windows - window_dispatch_update_all(); + //window_dispatch_update_all(); - if (RCT2_GLOBAL(0x009AC31B, uint8) != 0) { - stringId = STR_UNABLE_TO_LOAD_FILE; - _dx = RCT2_GLOBAL(0x009AC31C, uint16); - if (RCT2_GLOBAL(0x009AC31B, uint8) != 254) { - stringId = RCT2_GLOBAL(0x009AC31C, uint16); - _dx = 0xFFFF; + if (RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) != 0) { + rct_string_id title_text = STR_UNABLE_TO_LOAD_FILE; + rct_string_id body_text = RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16); + if (RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) == 254) { + title_text = RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16); + body_text = 0xFFFF; } - RCT2_GLOBAL(0x009AC31B, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0; - window_error_open(stringId, _dx); + window_error_open(title_text, body_text); } } @@ -343,7 +367,7 @@ static int game_check_affordability(int cost) } RCT2_GLOBAL(0x13CE952, uint32) = cost; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 827; - return 0x80000000; + return MONEY32_UNDEFINED; } static uint32 game_do_command_table[58]; @@ -386,7 +410,7 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * // Increment nest count RCT2_GLOBAL(0x009A8C28, uint8)++; - *ebx &= ~1; + *ebx &= ~GAME_COMMAND_FLAG_APPLY; // Primary command if (game_do_command_table[command] == 0) { @@ -396,13 +420,13 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * } cost = *ebx; - if (cost != 0x80000000) { + if (cost != MONEY32_UNDEFINED) { // Check funds insufficientFunds = 0; if (RCT2_GLOBAL(0x009A8C28, uint8) == 1 && !(flags & 4) && !(flags & 0x20) && cost != 0) insufficientFunds = game_check_affordability(cost); - if (insufficientFunds != 0x80000000) { + if (insufficientFunds != MONEY32_UNDEFINED) { *ebx = original_ebx; *edx = original_edx; *esi = original_esi; @@ -423,7 +447,7 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * } *edx = *ebx; - if (*edx != 0x80000000 && *edx < cost) + if (*edx != MONEY32_UNDEFINED && *edx < cost) cost = *edx; // Decrement nest count @@ -434,11 +458,11 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * // if (!(flags & 0x20)) { // Update money balance - finance_payment(cost, RCT2_GLOBAL(0x0141F56C, uint8)); + finance_payment(cost, RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) / 4); if (RCT2_GLOBAL(0x0141F568, uint8) == RCT2_GLOBAL(0x013CA740, uint8)) { // Create a +/- money text effect if (cost != 0) - RCT2_CALLPROC_X(0x0069C5D0, 0, cost, 0, 0, 0, 0, 0); + money_effect_create(cost); } } @@ -455,91 +479,52 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * if (RCT2_GLOBAL(0x009A8C28, uint8) == 0 && (flags & 1) && RCT2_GLOBAL(0x0141F568, uint8) == RCT2_GLOBAL(0x013CA740, uint8) && !(flags & 8)) window_error_open(RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16), RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16)); - return 0x80000000; + return MONEY32_UNDEFINED; } +void pause_toggle() +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint32) ^= 1; + window_invalidate_by_class(WC_TOP_TOOLBAR); + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint32) & 1) + pause_sounds(); + else + unpause_sounds(); +} /** * * rct2: 0x00667C15 */ -void game_pause_toggle() +void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) { - char input_bl; - - #ifdef _MSC_VER - __asm mov input_bl, bl - #else - __asm__ ( "mov %[input_bl], bl " : [input_bl] "+m" (input_bl) ); - #endif - - - if (input_bl & 1) { - RCT2_GLOBAL(0x009DEA6E, uint32) ^= 1; - window_invalidate_by_class(WC_TOP_TOOLBAR); - if (RCT2_GLOBAL(0x009DEA6E, uint32) & 1) - pause_sounds(); - else - unpause_sounds(); - } - - #ifdef _MSC_VER - __asm mov ebx, 0 - #else - __asm__ ( "mov ebx, 0 " ); - #endif + if (*ebx & GAME_COMMAND_FLAG_APPLY) + pause_toggle(); + *ebx = 0; } /** * * rct2: 0x0066DB5F */ -static void game_load_or_quit() +static void game_load_or_quit(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) { - char input_bl, input_dl; - short input_di; - - #ifdef _MSC_VER - __asm mov input_bl, bl - #else - __asm__ ( "mov %[input_bl], bl " : [input_bl] "+m" (input_bl) ); - #endif - - #ifdef _MSC_VER - __asm mov input_dl, dl - #else - __asm__ ( "mov %[input_dl], dl " : [input_dl] "+m" (input_dl) ); - #endif - - #ifdef _MSC_VER - __asm mov input_di, di - #else - __asm__ ( "mov %[input_di], di " : [input_di] "+m" (input_di) ); - #endif - - if (!(input_bl & 1)) - return; // 0; - - switch (input_dl) { - case 0: - RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16) = input_di; - window_save_prompt_open(); - break; - case 1: - window_close_by_class(WC_SAVE_PROMPT); - break; - default: - game_load_or_quit_no_save_prompt(); - break; + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + switch (*edx & 0xFF) { + case 0: + RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16) = *edi & 0xFF; + window_save_prompt_open(); + break; + case 1: + window_close_by_class(WC_SAVE_PROMPT); + break; + default: + game_load_or_quit_no_save_prompt(); + break; + } } - -#ifdef _MSC_VER - __asm mov ebx, 0 -#else - __asm__ ( "mov ebx, 0 " ); -#endif - + *ebx = 0; } /** @@ -553,7 +538,7 @@ static int open_landscape_file_dialog() strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_LANDSCAPES_PATH); format_string((char*)0x0141EE68, STR_RCT2_LANDSCAPE_FILE, 0); pause_sounds(); - result = osinterface_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6;*.SV4;*.SC6", (char*)0x0141EE68); + result = platform_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6;*.SV4;*.SC6", (char*)0x0141EE68); unpause_sounds(); // window_proc return result; @@ -570,7 +555,7 @@ static int open_load_game_dialog() strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH); format_string((char*)0x0141EE68, STR_RCT2_SAVED_GAME, 0); pause_sounds(); - result = osinterface_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6", (char*)0x0141EE68); + result = platform_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6", (char*)0x0141EE68); unpause_sounds(); // window_proc return result; @@ -582,6 +567,9 @@ static int open_load_game_dialog() */ static void load_landscape() { + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE, NULL); + return; + if (open_landscape_file_dialog() == 0) { gfx_invalidate_screen(); } else { @@ -613,20 +601,24 @@ static void load_landscape() * * rct2: 0x00675E1B */ -int game_load_save(const char *path) +int game_load_sv6(const char *path) { - rct_window *mainWindow; FILE *file; int i, j; log_verbose("loading saved game, %s", path); strcpy((char*)0x0141EF68, path); + strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path); + + strcpy(gScenarioSaveName, path_get_filename(path)); + path_remove_extension(gScenarioSaveName); + file = fopen(path, "rb"); if (file == NULL) { log_error("unable to open %s", path); - RCT2_GLOBAL(0x009AC31B, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; return 0; } @@ -636,7 +628,7 @@ int game_load_save(const char *path) log_error("invalid checksum, %s", path); - RCT2_GLOBAL(0x009AC31B, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; return 0; } @@ -671,26 +663,39 @@ int game_load_save(const char *path) fclose(file); - // Check expansion pack - // RCT2_CALLPROC_EBPSAFE(0x006757E6); - if (!load_success){ set_load_objects_fail_reason(); - if (RCT2_GLOBAL(0x9DE518,uint32) & (1<<5)){ + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5){ RCT2_GLOBAL(0x14241BC, uint32) = 2; //call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless RCT2_GLOBAL(0x14241BC, uint32) = 0; - RCT2_GLOBAL(0x9DE518, uint32) &= ~(1<<5); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5; } - title_load(); - rct2_endupdate(); + return 0;//This never gets called } // The rest is the same as in scenario load and play - RCT2_CALLPROC_EBPSAFE(0x006A9FC0); + reset_loaded_objects(); map_update_tile_pointers(); - reset_0x69EBE4();// RCT2_CALLPROC_EBPSAFE(0x0069EBE4); + reset_0x69EBE4(); + return 1; +} + +/** + * + * rct2: 0x00675E1B + */ +int game_load_save(const char *path) +{ + rct_window *mainWindow; + + if (!game_load_sv6(path)) { + title_load(); + rct2_endupdate(); + return 0; + } + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; viewport_init_all(); game_create_windows(); @@ -716,23 +721,26 @@ int game_load_save(const char *path) mainWindow->saved_view_y -= mainWindow->viewport->view_height >> 1; window_invalidate(mainWindow); - sub_69E9A7(); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); + reset_all_sprite_quadrant_placements(); + scenery_set_default_placement_configuration(); window_new_ride_init_vars(); RCT2_GLOBAL(0x009DEB7C, uint16) = 0; if (RCT2_GLOBAL(0x0013587C4, uint32) == 0) // this check is not in scenario play sub_69E869(); - RCT2_CALLPROC_EBPSAFE(0x006837E3); // (palette related) + load_palette(); gfx_invalidate_screen(); + + scenario_set_filename((char*)0x0135936C); return 1; } /* * * rct2: 0x0069E9A7 + * Call after a rotation or loading of a save to reset sprite quadrants */ -void sub_69E9A7() +void reset_all_sprite_quadrant_placements() { for (rct_sprite* spr = g_sprite_list; spr < (rct_sprite*)RCT2_ADDRESS_SPRITES_NEXT_INDEX; spr++) if (spr->unknown.sprite_identifier != 0xFF) @@ -745,6 +753,9 @@ void sub_69E9A7() */ static void load_game() { + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME, NULL); + return; + if (open_load_game_dialog() == 0) { gfx_invalidate_screen(); } else { @@ -789,7 +800,7 @@ static int show_save_game_dialog(char *resultPath) format_string(filterName, STR_RCT2_SAVED_GAME, NULL); pause_sounds(); - result = osinterface_open_common_file_dialog(0, title, filename, "*.SV6", filterName); + result = platform_open_common_file_dialog(0, title, filename, "*.SV6", filterName); unpause_sounds(); if (result) @@ -799,6 +810,9 @@ static int show_save_game_dialog(char *resultPath) char save_game() { + window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME, gScenarioSaveName); + return 0; + char path[256]; if (!show_save_game_dialog(path)) { @@ -809,8 +823,8 @@ char save_game() // Ensure path has .SV6 extension path_set_extension(path, ".SV6"); - if (scenario_save(path, gGeneral_config.save_plugin_data ? 1 : 0)) { - game_do_command(0, 1047, 0, -1, GAME_COMMAND_0, 0, 0); + if (scenario_save(path, gConfigGeneral.save_plugin_data ? 1 : 0)) { + game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); gfx_invalidate_screen(); return 1; } else { @@ -818,6 +832,36 @@ char save_game() } } +void game_autosave() +{ + char path[MAX_PATH]; + + platform_get_user_directory(path, "save"); + strcat(path, "autosave.sv6"); + + scenario_save(path, 0x80000000); +} + +/** +* +* rct2: 0x006E3838 +*/ +void rct2_exit_reason(rct_string_id title, rct_string_id body){ + // Before this would set a quit message + + char exit_title[255]; + format_string(exit_title, title, 0); + + char exit_body[255]; + format_string(exit_body, body, 0); + + log_error(exit_title); + log_error(exit_body); + + rct2_exit(); +} + + /** * * rct2: 0x006E3879 @@ -826,6 +870,7 @@ void rct2_exit() { RCT2_CALLPROC_EBPSAFE(0x006E3879); //Post quit message does not work in 0x6e3879 as its windows only. + openrct2_finish(); } /** @@ -843,10 +888,12 @@ void game_load_or_quit_no_save_prompt() load_game(); } else if (RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16) == 1) { game_do_command(0, 1, 0, 1, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + tool_cancel(); if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { RCT2_CALLPROC_EBPSAFE(0x0040705E); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5; } + gGameSpeed = 1; title_load(); rct2_endupdate(); } else { @@ -857,62 +904,62 @@ void game_load_or_quit_no_save_prompt() #pragma region Game command function table static uint32 game_do_command_table[58] = { - 0x006B2FC5, + 0, 0x0066397F, - (uint32)game_pause_toggle, + 0, 0x006C511D, 0x006C5B69, - (uint32)game_load_or_quit, + 0, 0x006B3F0F, - 0x006B49D9, - 0x006B4EA6, + 0, + 0, 0x006B52D4, - 0x006B578B, // 10 - 0x006B5559, + 0, // 10 + 0, 0x006660A8, 0x0066640B, - 0x006E0E01, - 0x006E08F4, + 0, + 0, 0x006E650F, - 0x006A61DE, + 0, 0x006A68AE, - 0x006A67C0, - 0x00663CCD, // 20 - 0x006B53E9, + 0, + 0, // use new_game_command_table, original: 0x00663CCD, // 20 + 0,//0x006B53E9, 0x00698D6C, // text input - 0x0068C542, - 0x0068C6D1, + 0, + 0, 0x0068BC01, - 0x006E66A0, - 0x006E6878, + 0, + 0, 0x006C5AE9, 0, // use new_game_command_table, original: 0x006BEFA1, 29 - 0x006C09D1, // 30 - 0x006C0B83, - 0x006C0BB5, - 0x00669C6D, - 0x00669D4A, - 0x006649BD, + 0, // 30 + 0, + 0, + 0, + 0, + 0,//0x006649BD, //buy_land_rights 0x006666E7, - 0x00666A63, + 0, 0x006CD8CE, - (uint32)game_command_set_park_entrance_fee, - (uint32)game_command_update_staff_colour, // 40 + 0, + 0, // 40 0x006E519A, - 0x006E5597, - 0x006B893C, - 0x006B8E1B, - 0x0069DFB3, - 0x00684A7F, - 0x006D13FE, - 0x0069E73C, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0x006CDEE4, - 0x006B9E6D, // 50 - 0x006BA058, - 0x006E0F26, - 0x006E56B5, - 0x006B909A, - 0x006BA16A, + 0, // 50 + 0, + 0, + 0, + 0, + 0, 0x006648E3, 0 }; @@ -920,62 +967,62 @@ static uint32 game_do_command_table[58] = { void game_command_emptysub(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) {} static GAME_COMMAND_POINTER* new_game_command_table[58] = { + game_command_set_ride_appearance, + game_command_emptysub, + game_pause_toggle, game_command_emptysub, game_command_emptysub, + game_load_or_quit, + game_command_emptysub, + game_command_demolish_ride, + game_command_set_ride_status, + game_command_emptysub, + game_command_set_ride_name, // 10 + game_command_set_ride_setting, game_command_emptysub, game_command_emptysub, + game_command_remove_scenery, + game_command_place_scenery, game_command_emptysub, + game_command_place_footpath, game_command_emptysub, + game_command_remove_footpath, + game_command_change_surface_style, // 20 + game_command_set_ride_price, game_command_emptysub, + game_command_raise_land, + game_command_lower_land, game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, // 10 - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, // 20 - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, + game_command_raise_water, + game_command_lower_water, game_command_emptysub, game_command_hire_new_staff_member, //game_command_emptysub, - game_command_emptysub, // 30 - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, // 40 - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, - game_command_emptysub, // 50 - game_command_emptysub, + game_command_set_staff_patrol, // 30 + game_command_fire_staff_member, + game_command_set_staff_order, + game_command_set_park_name, + game_command_set_park_open, + game_command_buy_land_rights, //game_command_emptysub,//game_command_buy_land_rights, game_command_emptysub, + game_command_remove_park_entrance, game_command_emptysub, + game_command_set_park_entrance_fee, + game_command_update_staff_colour, // 40 game_command_emptysub, + game_command_remove_fence, + game_command_place_large_scenery, + game_command_remove_large_scenery, + game_command_set_current_loan, + game_command_set_research_funding, + game_command_place_track, + game_command_start_campaign, game_command_emptysub, + game_command_place_banner, // 50 + game_command_remove_banner, + game_command_set_scenery_colour, + game_command_set_fence_colour, + game_command_set_large_scenery_colour, + game_command_set_banner_colour, game_command_emptysub, game_command_clear_scenery }; diff --git a/src/game.h b/src/game.h index 64a6f02c7d..219689e810 100644 --- a/src/game.h +++ b/src/game.h @@ -21,8 +21,10 @@ #ifndef _GAME_H_ #define _GAME_H_ +#include "common.h" + enum GAME_COMMAND { - GAME_COMMAND_0, + GAME_COMMAND_SET_RIDE_APPEARANCE, GAME_COMMAND_1, GAME_COMMAND_TOGGLE_PAUSE, // 2 GAME_COMMAND_3, //Has something to do with ride construction @@ -30,50 +32,50 @@ enum GAME_COMMAND { GAME_COMMAND_LOAD_OR_QUIT, // 5 GAME_COMMAND_6, GAME_COMMAND_7, - GAME_COMMAND_SET_RIDE_OPEN, // 8 + GAME_COMMAND_SET_RIDE_STATUS, // 8 GAME_COMMAND_9, GAME_COMMAND_SET_RIDE_NAME, - GAME_COMMAND_11, + GAME_COMMAND_SET_RIDE_SETTING, GAME_COMMAND_12, GAME_COMMAND_13, GAME_COMMAND_REMOVE_SCENERY, - GAME_COMMAND_15, + GAME_COMMAND_PLACE_SCENERY, GAME_COMMAND_16, GAME_COMMAND_PLACE_PATH, // 17 GAME_COMMAND_18, GAME_COMMAND_REMOVE_PATH, // 19 - GAME_COMMAND_20, - GAME_COMMAND_21, + GAME_COMMAND_CHANGE_SURFACE_STYLE, //20 + GAME_COMMAND_SET_RIDE_PRICE, GAME_COMMAND_22, //To do with text input - GAME_COMMAND_23, - GAME_COMMAND_24, - GAME_COMMAND_25, - GAME_COMMAND_26, - GAME_COMMAND_27, + GAME_COMMAND_RAISE_LAND, + GAME_COMMAND_LOWER_LAND, + GAME_COMMAND_EDIT_LAND_SMOOTH, + GAME_COMMAND_RAISE_WATER, + GAME_COMMAND_LOWER_WATER, GAME_COMMAND_28, GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, // 29 GAME_COMMAND_SET_STAFF_PATROL, //30 GAME_COMMAND_FIRE_STAFF_MEMBER, // 31 GAME_COMMAND_SET_STAFF_ORDER, // 32 - GAME_COMMAND_33, + GAME_COMMAND_SET_PARK_NAME, GAME_COMMAND_SET_PARK_OPEN, // 34 - GAME_COMMAND_35, - GAME_COMMAND_36, - GAME_COMMAND_37, + GAME_COMMAND_BUY_LAND_RIGHTS, // 35 + GAME_COMMAND_PLACE_PARK_ENTRANCE, + GAME_COMMAND_REMOVE_PARK_ENTRANCE, GAME_COMMAND_38, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, // 39 GAME_COMMAND_SET_STAFF_COLOUR, // 40 GAME_COMMAND_41, GAME_COMMAND_REMOVE_FENCE, - GAME_COMMAND_43, - GAME_COMMAND_44, + GAME_COMMAND_PLACE_LARGE_SCENERY, + GAME_COMMAND_REMOVE_LARGE_SCENERY, GAME_COMMAND_SET_CURRENT_LOAN, // 45 GAME_COMMAND_SET_RESEARCH_FUNDING, // 46 - GAME_COMMAND_47, + GAME_COMMAND_PLACE_TRACK, GAME_COMMAND_START_MARKETING_CAMPAIGN, // 48 GAME_COMMAND_49, - GAME_COMMAND_50, - GAME_COMMAND_51, + GAME_COMMAND_PLACE_BANNER, // New banner? (possibly scenery) + GAME_COMMAND_REMOVE_BANNER, // Remove banner GAME_COMMAND_52, GAME_COMMAND_53, GAME_COMMAND_54, @@ -82,6 +84,9 @@ enum GAME_COMMAND { GAME_COMMAND_CLEAR_SCENERY }; +// If this flag is set, the command is applied, otherwise only the cost is retrieved +#define GAME_COMMAND_FLAG_APPLY (1 << 0) + typedef void (GAME_COMMAND_POINTER)(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); extern int gGameSpeed; @@ -92,7 +97,7 @@ void game_reduce_game_speed(); void game_create_windows(); void game_update(); void game_logic_update(); -void sub_69E9A7(); +void reset_all_sprite_quadrant_placements(); void update_palette_effects(); int game_do_command(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); @@ -102,9 +107,13 @@ void game_increase_game_speed(); void game_reduce_game_speed(); void game_load_or_quit_no_save_prompt(); +int game_load_sv6(const char *path); int game_load_save(const char *path); -void game_pause_toggle(); +void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void pause_toggle(); char save_game(); void rct2_exit(); +void rct2_exit_reason(rct_string_id title, rct_string_id body); +void game_autosave(); #endif diff --git a/src/input.c b/src/input.c index 3d1b67ce1f..dce56db016 100644 --- a/src/input.c +++ b/src/input.c @@ -22,14 +22,16 @@ #include "addresses.h" #include "audio/audio.h" #include "config.h" +#include "cursors.h" #include "game.h" #include "input.h" +#include "interface/console.h" #include "interface/keyboard_shortcut.h" #include "interface/viewport.h" #include "interface/widget.h" #include "interface/window.h" #include "localisation/localisation.h" -#include "platform/osinterface.h" +#include "platform/platform.h" #include "ride/ride_data.h" #include "scenario.h" #include "tutorial.h" @@ -70,7 +72,6 @@ void game_handle_key_scroll(); static void input_widget_left(int x, int y, rct_window *w, int widgetIndex); void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_window* w, rct_widget* widget); void sub_6ED990(char cursor_id); -static void input_window_position_begin(rct_window *w, int widgetIndex, int x, int y); static void input_window_position_continue(rct_window *w, int lastX, int lastY, int newX, int newY); static void input_window_position_end(rct_window *w, int x, int y); static void input_window_resize_begin(rct_window *w, int widgetIndex, int x, int y); @@ -82,7 +83,15 @@ static void input_viewport_drag_end(); static void input_scroll_begin(); static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int x, int y); static void input_scroll_end(); +static void input_scroll_part_update_hthumb(rct_window *w, int widgetIndex, int x, int scroll_id); +static void input_scroll_part_update_hleft(rct_window *w, int widgetIndex, int scroll_id); +static void input_scroll_part_update_hright(rct_window *w, int widgetIndex, int scroll_id); +static void input_scroll_part_update_vthumb(rct_window *w, int widgetIndex, int y, int scroll_id); +static void input_scroll_part_update_vtop(rct_window *w, int widgetIndex, int scroll_id); +static void input_scroll_part_update_vbottom(rct_window *w, int widgetIndex, int scroll_id); static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y); +static void update_cursor_position(); +static void sub_6EA2AA(rct_window *w, int widgetIndex, int x, int y, int edi); #pragma region Mouse input @@ -97,15 +106,15 @@ void game_handle_input() if (RCT2_GLOBAL(0x009DEA64, uint16) & 2) { RCT2_GLOBAL(0x009DEA64, uint16) &= ~2; - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 2, 0); + game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 2, 0); } if (RCT2_GLOBAL(0x009ABDF2, uint8) != 0) { for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_07], 0, 0, 0, 0, (int)w, 0, 0); + window_event_unknown_07_call(w); sub_6EA73F(); - RCT2_CALLPROC_EBPSAFE(0x006E8346); // update_cursor_position + update_cursor_position(); for (;;) { game_get_next_input(&x, &y, &state); @@ -117,7 +126,8 @@ void game_handle_input() if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { game_handle_input_mouse(x, y, state); - } else if (x != 0x80000000) { + } + else if (x != 0x80000000) { x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 1); y = clamp(0, y, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - 1); @@ -128,13 +138,13 @@ void game_handle_input() } for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_08], 0, 0, 0, 0,(int) w, 0, 0); + window_event_unknown_08_call(w); } /** * * rct2: 0x006E83C7 - */ +*/ static void game_get_next_input(int *x, int *y, int *state) { rct_mouse_data* eax = get_mouse_input(); @@ -149,31 +159,11 @@ static void game_get_next_input(int *x, int *y, int *state) *y = eax->y; *state = eax->state; - //int eax, ebx, ecx, edx, esi, edi, ebp; - //RCT2_CALLFUNC_X(0x006E83C7, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - //*x = eax & 0xFFFF; - //*y = ebx & 0xFFFF; - //*state = ecx & 0xFF; - //return; - - //int on_tutorial = RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8); - //if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { - // if (on_tutorial == 1) { - - // } else { - // RCT2_CALLPROC_EBPSAFE(0x00407074); - // } - // if (on_tutorial == 2) { - - // } - - //} else { - - //} + // NOTE this function lacks tutorial logic } /** - * + * * rct2: 0x00407074 */ static rct_mouse_data* get_mouse_input() @@ -217,17 +207,18 @@ static void game_handle_input_mouse(int x, int y, int state) break; case 3: window_close_by_class(WC_TOOLTIP); - + if (w != NULL) w = window_bring_to_front(w); - + if (widgetIndex == -1) break; - + if (widget->type == WWT_VIEWPORT) { if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO))) input_viewport_drag_begin(w, x, y); - } else if (widget->type == WWT_SCROLL) { + } + else if (widget->type == WWT_SCROLL) { } break; @@ -241,7 +232,8 @@ static void game_handle_input_mouse(int x, int y, int state) w = window_find_by_number(_dragWindowClass, _dragWindowNumber); if (w == NULL) { RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; - } else { + } + else { input_window_position_continue(w, _dragX, _dragY, x, y); if (state == 2) input_window_position_end(w, x, y); @@ -250,7 +242,8 @@ static void game_handle_input_mouse(int x, int y, int state) case INPUT_STATE_VIEWPORT_RIGHT: if (state == 0) { input_viewport_drag_continue(); - } else if (state == 4) { + } + else if (state == 4) { input_viewport_drag_end(); if (RCT2_GLOBAL(0x009DE540, sint16) < 500) { viewport_interaction_right_click(x, y); @@ -261,11 +254,10 @@ static void game_handle_input_mouse(int x, int y, int state) input_state_widget_pressed(x, y, state, widgetIndex, w, widget); break; case INPUT_STATE_VIEWPORT_LEFT: - //RCT2_CALLPROC_X(0x006E87B4, x, y, state, widgetIndex, (int)w, (int)widget, 0); w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) - ); + ); if (!w){ RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; break; @@ -279,32 +271,32 @@ static void game_handle_input_mouse(int x, int y, int state) if (w->classification != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) || w->number != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) || - !(RCT2_GLOBAL(0x9DE518, uint32)&(1 << 3)))break; - + !(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) break; + w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) - ); + ); if (w == NULL) break; - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DRAG], x, y, 0, (int)RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0); + window_event_tool_drag_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint32), x, y); } else if (state == 2){ - + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; if (RCT2_GLOBAL(0x9DE52E, rct_windownumber) != w->number)break; - if ((RCT2_GLOBAL(0x9DE518, uint32)&(1 << 3))){ + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)){ w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) - ); + ); if (w == NULL) break; - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UP], x, y, 0, (int)RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0); + window_event_tool_up_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), x, y); } else{ - if ((RCT2_GLOBAL(0x9DE518, uint32) & (1 << 4))) + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_4)) break; viewport_interaction_left_click(x, y); @@ -321,7 +313,8 @@ static void game_handle_input_mouse(int x, int y, int state) w = window_find_by_number(_dragWindowClass, _dragWindowNumber); if (w == NULL) { RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; - } else { + } + else { if (state == 2) input_window_resize_end(); @@ -334,10 +327,10 @@ static void game_handle_input_mouse(int x, int y, int state) break; } } - + #pragma region Window positioning / resizing -static void input_window_position_begin(rct_window *w, int widgetIndex, int x, int y) +void input_window_position_begin(rct_window *w, int widgetIndex, int x, int y) { RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_POSITIONING_WINDOW; _dragX = x - w->x; @@ -349,7 +342,10 @@ static void input_window_position_begin(rct_window *w, int widgetIndex, int x, i static void input_window_position_continue(rct_window *w, int wdx, int wdy, int x, int y) { - window_move_and_snap(w, x - wdx, y - wdy, gGeneral_config.window_snap_proximity); + int snapProximity; + + snapProximity = w->flags & WF_NO_SNAPPING ? 0 : gConfigGeneral.window_snap_proximity; + window_move_and_snap(w, x - wdx, y - wdy, snapProximity); } static void input_window_position_end(rct_window *w, int x, int y) @@ -359,7 +355,7 @@ static void input_window_position_end(rct_window *w, int x, int y) RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = _dragWindowClass; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = _dragWindowNumber; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = _dragWidgetIndex; - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_18], 0, 0, x, y, (int)w, 0, 0); + window_event_moved_call(w, x, y); } static void input_window_resize_begin(rct_window *w, int widgetIndex, int x, int y) @@ -388,7 +384,7 @@ static void input_window_resize_continue(rct_window *w, int x, int y) w, targetWidth - w->width, targetHeight - w->height - ); + ); } } @@ -476,10 +472,10 @@ static void input_scroll_begin(rct_window *w, int widgetIndex, int x, int y) widget_scroll_get_part(w, widget, x, y, &eax, &ebx, &scroll_area, &scroll_id); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16) = scroll_area; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32) = scroll_id * sizeof(rct_scroll);//We do this because scroll id is not all decompiled - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_15], RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32), ebx, scroll_area, scroll_id, (int)w, (int)widget, 0); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32) = scroll_id * sizeof(rct_scroll); + window_event_unknown_15_call(w, scroll_id, scroll_area); if (scroll_area == SCROLL_PART_VIEW){ - RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEDOWN], scroll_id / sizeof(rct_scroll), ebx, eax, ebx, (int)w, (int)widget, 0); + window_event_scroll_mousedown_call(w, scroll_id, eax, ebx); return; } @@ -531,6 +527,7 @@ static void input_scroll_begin(rct_window *w, int widgetIndex, int x, int y) static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int x, int y) { rct_widget *widget; + int scroll_part, scroll_id; widget = &w->widgets[widgetIndex]; if (widgetIndex != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32)){ @@ -545,24 +542,24 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int invalidate_scroll(); return; } - + + widget_scroll_get_part(w, widget, x, y, &x, &y, &scroll_part, &scroll_id); + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16) == SCROLL_PART_HSCROLLBAR_THUMB){ int temp_x = x; x -= RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16); RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) = temp_x; - RCT2_CALLPROC_X(0x006E98F2, x, temp_x, state, w->number, (int)w, (int)widget, x); + input_scroll_part_update_hthumb(w, widgetIndex, x, scroll_id); return; } if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16) == SCROLL_PART_VSCROLLBAR_THUMB){ - int temp_y = y; + int temp_y = y; y -= RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16); RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) = temp_y; - RCT2_CALLPROC_X(0x006E99A9, temp_y, y, state, w->number, (int)w, (int)widget, y); + input_scroll_part_update_vthumb(w, widgetIndex, y, scroll_id); return; } - int scroll_part, scroll_id; - widget_scroll_get_part(w, widget, x, y, &x, &y, &scroll_part, &scroll_id); if (scroll_part != RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16)){ invalidate_scroll(); @@ -571,13 +568,13 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int switch (scroll_part){ case SCROLL_PART_VIEW: - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DRAG], w->number / 18, y, x, y, (int)w, (int)widget, (int)w->event_handlers); + window_event_tool_drag_call(w, widgetIndex, w->number / 18, y); break; case SCROLL_PART_HSCROLLBAR_LEFT: - RCT2_CALLPROC_X(0x006E9A60, x, y, scroll_part, w->number, (int)w, (int)widget, 0); + input_scroll_part_update_hleft(w, widgetIndex, scroll_id); break; case SCROLL_PART_HSCROLLBAR_RIGHT: - RCT2_CALLPROC_X(0x006E9ABF, x, y, scroll_part, w->number, (int)w, (int)widget, 0); + input_scroll_part_update_hright(w, widgetIndex, scroll_id); break; case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH: @@ -585,10 +582,10 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int break; case SCROLL_PART_HSCROLLBAR_THUMB: case SCROLL_PART_VSCROLLBAR_TOP: - RCT2_CALLPROC_X(0x006E9C37, x, y, scroll_part, w->number, (int)w, (int)widget, 0); + input_scroll_part_update_vtop(w, widgetIndex, scroll_id); break; case SCROLL_PART_VSCROLLBAR_BOTTOM: - RCT2_CALLPROC_X(0x006E9C96, x, y, scroll_part, w->number, (int)w, (int)widget, 0); + input_scroll_part_update_vbottom(w, widgetIndex, scroll_id); break; case SCROLL_PART_VSCROLLBAR_TOP_TROUGH: case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH: @@ -601,10 +598,164 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int static void input_scroll_end() { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; invalidate_scroll(); } +/** + * + * rct: 0x006E98F2 + */ +static void input_scroll_part_update_hthumb(rct_window *w, int widgetIndex, int x, int scroll_id) +{ + rct_widget *widget = &w->widgets[widgetIndex]; + int newLeft; + + if (window_find_by_number(w->classification, w->number)) { + newLeft = w->scrolls[scroll_id].h_right; + newLeft *= x; + x = widget->right - widget->left - 21; + if (w->scrolls[scroll_id].flags & VSCROLLBAR_VISIBLE) + x -= 11; + newLeft /= x; + x = newLeft; + w->scrolls[scroll_id].flags |= HSCROLLBAR_THUMB_PRESSED; + newLeft = w->scrolls[scroll_id].h_left; + newLeft += x; + if (newLeft < 0) + newLeft = 0; + x = widget->right - widget->left - 1; + if (w->scrolls[scroll_id].flags & VSCROLLBAR_VISIBLE) + x -= 11; + x *= -1; + x += w->scrolls[scroll_id].h_right; + if (x < 0) + x = 0; + if (newLeft > x) + newLeft = x; + w->scrolls[scroll_id].h_left = newLeft; + widget_scroll_update_thumbs(w, widgetIndex); + widget_invalidate_by_number(w->classification, w->number, widgetIndex); + } +} + +/** + * + * rct: 0x006E99A9 + */ +static void input_scroll_part_update_vthumb(rct_window *w, int widgetIndex, int y, int scroll_id) +{ + rct_widget *widget = &w->widgets[widgetIndex]; + int newTop; + + if (window_find_by_number(w->classification, w->number)) { + newTop = w->scrolls[scroll_id].v_bottom; + newTop *= y; + y = widget->bottom - widget->top - 21; + if (w->scrolls[scroll_id].flags & HSCROLLBAR_VISIBLE) + y -= 11; + newTop /= y; + y = newTop; + w->scrolls[scroll_id].flags |= VSCROLLBAR_THUMB_PRESSED; + newTop = w->scrolls[scroll_id].v_top; + newTop += y; + if (newTop < 0) + newTop = 0; + y = widget->bottom - widget->top - 1; + if (w->scrolls[scroll_id].flags & HSCROLLBAR_VISIBLE) + y -= 11; + y *= -1; + y += w->scrolls[scroll_id].v_bottom; + if (y < 0) + y = 0; + if (newTop > y) + newTop = y; + w->scrolls[scroll_id].v_top = newTop; + widget_scroll_update_thumbs(w, widgetIndex); + widget_invalidate_by_number(w->classification, w->number, widgetIndex); + } +} + +/** + * + * rct: 0x006E9A60 + */ +static void input_scroll_part_update_hleft(rct_window *w, int widgetIndex, int scroll_id) +{ + if (window_find_by_number(w->classification, w->number)) { + w->scrolls[scroll_id].flags |= HSCROLLBAR_LEFT_PRESSED; + w->scrolls[scroll_id].h_left -= 3; + if (w->scrolls[scroll_id].h_left < 0) + w->scrolls[scroll_id].h_left = 0; + widget_scroll_update_thumbs(w, widgetIndex); + widget_invalidate_by_number(w->classification, w->number, widgetIndex); + } +} + +/** + * + * rct: 0x006E9ABF + */ +static void input_scroll_part_update_hright(rct_window *w, int widgetIndex, int scroll_id) +{ + rct_widget *widget = &w->widgets[widgetIndex]; + if (window_find_by_number(w->classification, w->number)) { + w->scrolls[scroll_id].flags |= HSCROLLBAR_RIGHT_PRESSED; + w->scrolls[scroll_id].h_left += 3; + int newLeft = widget->right - widget->left - 1; + if (w->scrolls[scroll_id].flags & VSCROLLBAR_VISIBLE) + newLeft -= 11; + newLeft *= -1; + newLeft += w->scrolls[scroll_id].h_right; + if (newLeft < 0) + newLeft = 0; + if (w->scrolls[scroll_id].h_left > newLeft) + w->scrolls[scroll_id].h_left = newLeft; + widget_scroll_update_thumbs(w, widgetIndex); + widget_invalidate_by_number(w->classification, w->number, widgetIndex); + } +} + +/** + * + * rct: 0x006E9C37 + */ +static void input_scroll_part_update_vtop(rct_window *w, int widgetIndex, int scroll_id) +{; + if (window_find_by_number(w->classification, w->number)) { + w->scrolls[scroll_id].flags |= VSCROLLBAR_UP_PRESSED; + w->scrolls[scroll_id].v_top -= 3; + if (w->scrolls[scroll_id].v_top < 0) + w->scrolls[scroll_id].v_top = 0; + widget_scroll_update_thumbs(w, widgetIndex); + widget_invalidate_by_number(w->classification, w->number, widgetIndex); + } +} + +/** + * + * rct: 0x006E9C96 + */ +static void input_scroll_part_update_vbottom(rct_window *w, int widgetIndex, int scroll_id) +{ + rct_widget *widget = &w->widgets[widgetIndex]; + if (window_find_by_number(w->classification, w->number)) { + w->scrolls[scroll_id].flags |= VSCROLLBAR_DOWN_PRESSED; + w->scrolls[scroll_id].v_top += 3; + int newTop = widget->bottom - widget->top - 1; + if (w->scrolls[scroll_id].flags & HSCROLLBAR_VISIBLE) + newTop -= 11; + newTop *= -1; + newTop += w->scrolls[scroll_id].v_bottom; + if (newTop < 0) + newTop = 0; + if (w->scrolls[scroll_id].v_top > newTop) + w->scrolls[scroll_id].v_top = newTop; + widget_scroll_update_thumbs(w, widgetIndex); + widget_invalidate_by_number(w->classification, w->number, widgetIndex); + } +} + #pragma endregion #pragma region Widgets @@ -630,14 +781,15 @@ static void input_widget_over(int x, int y, rct_window *w, int widgetIndex) if (w != NULL && widgetIndex != -1 && widget->type == WWT_SCROLL) { int eax, ebx, ecx, edx; widget_scroll_get_part(w, widget, x, y, &eax, &ebx, &ecx, &edx); - + if (ecx < 0) input_update_tooltip(w, widgetIndex, x, y); else if (ecx == 0) { - RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEOVER], edx, 0, eax, ebx, (int)w, 0, 0); + window_event_scroll_mouseover_call(w, edx, eax, ebx); input_update_tooltip(w, widgetIndex, x, y); } - } else { + } + else { input_update_tooltip(w, widgetIndex, x, y); } @@ -661,7 +813,7 @@ static void input_widget_over_change_check(rct_windowclass windowClass, rct_wind windowClass != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass) || windowNumber != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER, rct_windownumber) || widgetIndex != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, uint16) - ) { + ) { // Invalidate last widget cursor was on if widget is a flat button input_widget_over_flatbutton_invalidate(); @@ -685,7 +837,7 @@ static void input_widget_over_flatbutton_invalidate() rct_window *w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER, rct_windownumber) - ); + ); if (w == NULL) return; @@ -695,7 +847,7 @@ static void input_widget_over_flatbutton_invalidate() RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER, rct_windownumber), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, rct_windownumber) - ); + ); } } @@ -726,6 +878,12 @@ static void input_widget_left(int x, int y, rct_window *w, int widgetIndex) if (widgetIndex == -1) return; + if (windowClass != gCurrentTextBox.window.classification || + windowNumber != gCurrentTextBox.window.number || + widgetIndex != gCurrentTextBox.widget_index) { + window_cancel_textbox(); + } + widget = &w->widgets[widgetIndex]; switch (widget->type) { @@ -744,9 +902,9 @@ static void input_widget_left(int x, int y, rct_window *w, int widgetIndex) w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) - ); + ); if (w != NULL) { - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DOWN], x, y, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0); + window_event_tool_down_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint32), x, y); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_4; } } @@ -779,9 +937,9 @@ static void input_widget_left(int x, int y, rct_window *w, int widgetIndex) #pragma endregion /** -* + * * rct2: 0x006ED833 -*/ + */ void process_mouse_over(int x, int y) { rct_window* window; @@ -800,8 +958,9 @@ void process_mouse_over(int x, int y) RCT2_GLOBAL(0x1420046, sint16) = (widgetId & 0xFFFF); if (widgetId != -1) { switch (window->widgets[widgetId].type){ + case WWT_VIEWPORT: - if ((RCT2_GLOBAL(0x9DE518, int) & 0x8) == 0) { + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, int) & INPUT_FLAG_TOOL_ACTIVE) == 0) { if (viewport_interaction_left_over(x, y)) { sub_6ED990(CURSOR_HAND_POINT); return; @@ -812,15 +971,14 @@ void process_mouse_over(int x, int y) subWindow = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) - ); + ); ebp = (int)subWindow; if (subWindow == NULL) - { break; - } + ebx = ebx & 0xFFFFFF00; edi = cursorId; - esi = (int) subWindow; + esi = (int)subWindow; RCT2_CALLFUNC_X(subWindow->event_handlers[WE_UNKNOWN_0E], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); cursorId = edi; if ((ebx & 0xFF) != 0) @@ -829,31 +987,29 @@ void process_mouse_over(int x, int y) return; } break; + case WWT_FRAME: case WWT_RESIZE: if (!(window->flags & 0x100)) - { break; - } + if (window->min_width == window->max_width && window->min_height == window->max_height) - { break; - } + if (x < window->x + window->width - 0x13) - { break; - } + if (y < window->y + window->height - 0x13) - { break; - } + cursorId = CURSOR_DIAGONAL_ARROWS; break; + case WWT_SCROLL: RCT2_GLOBAL(0x9DE558, uint16) = x; RCT2_GLOBAL(0x9DE55A, uint16) = y; - int output_x, output_y, output_scroll_area, scroll_id; - widget_scroll_get_part(window, window->widgets, x, y, &output_x, &output_y, &output_scroll_area, &scroll_id); + int output_scroll_area, scroll_id; + widget_scroll_get_part(window, window->widgets, x, y, &x, &y, &output_scroll_area, &scroll_id); cursorId = scroll_id; if (output_scroll_area != SCROLL_PART_VIEW) { @@ -862,19 +1018,9 @@ void process_mouse_over(int x, int y) } //Fall through to default default: - ecx = x; - edx = y; - eax = widgetId; - ebx = 0xFFFFFFFF; - edi = (int)&window->widgets[widgetId]; - - RCT2_CALLFUNC_X(window->event_handlers[WE_UNKNOWN_17], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (ebx == 0xFFFFFFFF) - { + cursorId = window_event_cursor_call(window, widgetId, x, y); + if (cursorId == -1) cursorId = CURSOR_ARROW; - break; - } - cursorId = ebx; break; } } @@ -890,17 +1036,17 @@ void process_mouse_over(int x, int y) */ void process_mouse_tool(int x, int y) { - if (RCT2_GLOBAL(0x9DE518, uint32) & (1 << 3)) + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { rct_window* w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, uint16) - ); + ); if (!w) tool_cancel(); else - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UPDATE], x, y, 0, RCT2_GLOBAL(0x9DE546, uint16), (int)w, 0, 0); + window_event_tool_update_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint32), x, y); } } @@ -909,9 +1055,8 @@ void process_mouse_tool(int x, int y) * * rct2: 0x006E8DA7 */ -void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_window* w, rct_widget* widget ){ - //RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); - //return; +void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_window *w, rct_widget *widget) +{ RCT2_GLOBAL(0x1420054, uint16) = x; RCT2_GLOBAL(0x1420056, uint16) = y; @@ -921,7 +1066,7 @@ void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_w cursor_w_number = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber); int cursor_widgetIndex = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32); - rct_window* cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); + rct_window *cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); if (cursor_w == NULL) { RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; return; @@ -935,26 +1080,28 @@ void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_w if (w->disabled_widgets & (1ULL << widgetIndex)) break; - if (RCT2_GLOBAL(0x9DE528, uint16) != 0) RCT2_GLOBAL(0x9DE528, uint16)++; + if (RCT2_GLOBAL(0x009DE528, uint16) != 0) + RCT2_GLOBAL(0x009DE528, uint16)++; - if (w->var_020 & (1ULL << widgetIndex) && - RCT2_GLOBAL(0x9DE528, uint16) >= 0x10 && - (!(RCT2_GLOBAL(0x9DE528, uint16) & 0x3))){ + if (w->hold_down_widgets & (1ULL << widgetIndex) && + RCT2_GLOBAL(0x009DE528, uint16) >= 16 && + !(RCT2_GLOBAL(0x009DE528, uint16) & 3) + ) { window_event_mouse_down_call(w, widgetIndex); } - if (RCT2_GLOBAL(0x9DE518, uint32) & 1) return; + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_WIDGET_PRESSED) return; - RCT2_GLOBAL(0x9DE518, uint32) |= 1; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_WIDGET_PRESSED; widget_invalidate_by_number(cursor_w_class, cursor_w_number, widgetIndex); return; case 3: case 2: - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 5){ + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 5) { if (w) { int dropdown_index = 0; - if (w->classification == WC_DROPDOWN){ + if (w->classification == WC_DROPDOWN) { dropdown_index = dropdown_index_from_point(x, y, w); if (dropdown_index == -1)goto dropdown_cleanup; @@ -964,13 +1111,13 @@ void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_w // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)goto dropdown_cleanup; } - else{ + else { if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) goto dropdown_cleanup; dropdown_index = -1; - if (RCT2_GLOBAL(0x9DE518, uint32) & 2){ - if (!(RCT2_GLOBAL(0x9DE518, uint32) & 4)){ - RCT2_GLOBAL(0x9DE518, uint32) |= (1 << 2); + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_DROPDOWN_STAY_OPEN){ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_DROPDOWN_MOUSE_UP)){ + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_DROPDOWN_MOUSE_UP; return; } } @@ -978,8 +1125,8 @@ void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_w window_close_by_class(WC_DROPDOWN); cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); - if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ - RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_WIDGET_PRESSED) { + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= 0xFFFE; widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); } @@ -988,7 +1135,7 @@ void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_w RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = cursor_w_class; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = cursor_w_number; - RCT2_CALLPROC_X(cursor_w->event_handlers[WE_DROPDOWN], dropdown_index, 0, 0, cursor_widgetIndex, (int)cursor_w, 0, 0); + window_event_dropdown_call(cursor_w, cursor_widgetIndex, dropdown_index); } dropdown_cleanup: window_close_by_class(WC_DROPDOWN); @@ -1002,11 +1149,14 @@ void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_w if (!w) break; + if (!widget) + break; + int mid_point_x = (widget->left + widget->right) / 2 + w->x; sound_play_panned(5, mid_point_x, 0, 0, 0); if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) break; - + if (w->disabled_widgets & (1ULL << widgetIndex)) break; @@ -1019,8 +1169,8 @@ void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_w RCT2_GLOBAL(0x9DE528, uint16) = 0; if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) != 5){ // Hold down widget and drag outside of area?? - if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ - RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_WIDGET_PRESSED){ + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= 0xFFFE; widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); } return; @@ -1051,23 +1201,25 @@ static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y) if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) < 500 || (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, sint16) == x && RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, sint16) == y) - ) { + ) { RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = RCT2_GLOBAL(0x009DE588, uint16); int bp = 2000; - if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) <= 1000) + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) >= 1) bp = 0; - if (bp > RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16)) + if (bp > RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16)) { + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16)++; return; + } window_tooltip_open(w, widgetIndex, x, y); - // RCT2_CALLPROC_X(0x006EA10D, x, y, 0, widgetIndex, w, widget, 0); // window_tooltip_open(); } - } else { + } + else { if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) != w->classification || RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) != w->number || RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) != widgetIndex - ) { + ) { window_tooltip_close(); } RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) += RCT2_GLOBAL(0x009DE588, uint16); @@ -1089,6 +1241,7 @@ static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y) */ void title_handle_keyboard_input() { + rct_window *w; int key; // Handle modifier keys and key scrolling @@ -1108,7 +1261,11 @@ void title_handle_keyboard_input() key |= RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) << 8; - if (key == gShortcutKeys[SHORTCUT_SCREENSHOT]) { + w = window_find_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); + if (w != NULL) { + keyboard_shortcut_set(key); + } + else if (key == gShortcutKeys[SHORTCUT_SCREENSHOT]) { keyboard_shortcut_handle_command(SHORTCUT_SCREENSHOT); } } @@ -1123,24 +1280,26 @@ void game_handle_keyboard_input() rct_window *w; int key; - // Handle mouse scrolling - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0) - if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, uint8) != 0) - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 1) - if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 3)) - game_handle_edge_scroll(); - - // Handle modifier keys and key scrolling - RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = 0; - if (RCT2_GLOBAL(0x009E2B64, uint32) != 1) { - if (gKeysState[SDL_SCANCODE_LSHIFT] || gKeysState[SDL_SCANCODE_RSHIFT]) - RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 1; - if (gKeysState[SDL_SCANCODE_LCTRL] || gKeysState[SDL_SCANCODE_RCTRL]) - RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 2; - if (gKeysState[SDL_SCANCODE_LALT] || gKeysState[SDL_SCANCODE_RALT]) - RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 4; + if (!gConsoleOpen) { + // Handle mouse scrolling if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0) - game_handle_key_scroll(); + if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, uint8) != 0) + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 1) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 3)) + game_handle_edge_scroll(); + + // Handle modifier keys and key scrolling + RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = 0; + if (RCT2_GLOBAL(0x009E2B64, uint32) != 1) { + if (gKeysState[SDL_SCANCODE_LSHIFT] || gKeysState[SDL_SCANCODE_RSHIFT]) + RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 1; + if (gKeysState[SDL_SCANCODE_LCTRL] || gKeysState[SDL_SCANCODE_RCTRL]) + RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 2; + if (gKeysState[SDL_SCANCODE_LALT] || gKeysState[SDL_SCANCODE_RALT]) + RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 4; + if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0) + game_handle_key_scroll(); + } } @@ -1149,23 +1308,36 @@ void game_handle_keyboard_input() if (key == 255) continue; + // Reserve backtick for console + if (key == SDL_SCANCODE_GRAVE) { + if (gConfigGeneral.debugging_tools || gConsoleOpen) { + window_cancel_textbox(); + console_toggle(); + } + continue; + } else if (gConsoleOpen) { + console_input(key); + continue; + } + key |= RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) << 8; w = window_find_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); - if (w != NULL) + if (w != NULL) { keyboard_shortcut_set(key); - else if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 1) + } + else if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 1) { tutorial_stop(); - else{ + } + else { w = window_find_by_class(WC_TEXTINPUT); if (w != NULL){ - ((void(*)(int, rct_window*))w->event_handlers[WE_TEXT_INPUT])(key,w); + ((void(*)(int, rct_window*))w->event_handlers[WE_TEXT_INPUT])(key, w); } - else{ + else if (!gUsingWidgetTextBox) { keyboard_shortcut_handle(key); } } - } if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0) @@ -1184,11 +1356,12 @@ void game_handle_keyboard_input() RCT2_GLOBAL(0x009DEA72, uint16)++; } } - } else { + } + else { if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 4)) { window_tooltip_close(); if ((w = window_get_main()) != NULL) { - RCT2_CALLPROC_X(0x006EA2AA, 0, 0, 0, 0, (int)w, RCT2_GLOBAL(0x009DEA72, uint16), 0); + sub_6EA2AA(w, 0, 0, 0, RCT2_GLOBAL(0x009DEA72, uint16)); RCT2_GLOBAL(0x009DEA72, uint16)++; } } @@ -1198,6 +1371,48 @@ void game_handle_keyboard_input() } } +static void sub_6EA2AA(rct_window *w, int widgetIndex, int x, int y, int edi) +{ + RCT2_CALLPROC_X(0x006EA2AA, 0, 0, 0, 0, (int)w, RCT2_GLOBAL(0x009DEA72, uint16), 0); + return; + + rct_window *tooltipWindow; + + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = w->classification; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = w->number; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = widgetIndex; + + rct_string_id stringId = window_event_tooltip_call(w, widgetIndex); + if (stringId == (rct_string_id)STR_NONE) + return; + + tooltipWindow = window_find_by_class(WC_TOOLTIP); + if (tooltipWindow == NULL) + return; + + char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; + + RCT2_GLOBAL(0x0142006C, uint32) = edi; + format_string(buffer, edi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + int width = gfx_get_string_width_new_lined(buffer); + width = min(width, 196); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + + int numLines, fontHeight; + gfx_wrap_string(buffer, width + 1, &numLines, &fontHeight); + + RCT2_GLOBAL(0x01420044, uint16) = numLines; + tooltipWindow->widgets[0].right = width + 3; + tooltipWindow->widgets[0].bottom = ((numLines + 1) * 10) + 4; + + char *tooltipBuffer = (char*)RCT2_ADDRESS_TOOLTIP_TEXT_BUFFER; + memcpy(tooltipBuffer, buffer, 512); + + window_tooltip_open(w, widgetIndex, x, y); +} + /** * * rct2: 0x00406CD2 @@ -1233,7 +1448,7 @@ void sub_6ED990(char cursor_id){ } RCT2_GLOBAL(RCT2_ADDRESS_CURENT_CURSOR, uint8) = cursor_id; RCT2_GLOBAL(0x14241BC, uint32) = 2; - osinterface_set_cursor(cursor_id); + platform_set_cursor(cursor_id); RCT2_GLOBAL(0x14241BC, uint32) = 0; } @@ -1248,7 +1463,7 @@ void invalidate_scroll() rct_window* wind = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, uint8), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, uint16) - ); + ); if (wind == NULL) return; int scroll_id = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_ID, uint32); @@ -1258,7 +1473,7 @@ void invalidate_scroll() window_invalidate_by_number( RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, uint8), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, uint16) - ); + ); } /** @@ -1294,6 +1509,10 @@ void game_handle_edge_scroll() if (mainWindow->viewport == NULL) return; + uint32 window_flags = SDL_GetWindowFlags(gWindow); + if ((window_flags & SDL_WINDOW_INPUT_FOCUS) == 0) + return; + scrollX = 0; scrollY = 0; @@ -1336,7 +1555,7 @@ void game_handle_key_scroll() rct_window *textWindow; textWindow = window_find_by_class(WC_TEXTINPUT); - if (textWindow) return; + if (textWindow || gUsingWidgetTextBox) return; scrollX = 0; scrollY = 0; @@ -1362,4 +1581,23 @@ void game_handle_key_scroll() mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; } +} + +/** + * rct2: 0x006E8346 + */ +static void update_cursor_position() +{ + switch (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8)) { + case 0: + // RCT2_GLOBAL(0x0142004C, sint32) = RCT2_GLOBAL(0x0142406C, sint32); + // RCT2_GLOBAL(0x01420050, sint32) = RCT2_GLOBAL(0x01424070, sint32); + break; + case 1: + // read tutorial cursor position + break; + case 2: + // write tutorial cursor position + break; + } } \ No newline at end of file diff --git a/src/input.h b/src/input.h index 80f75ad920..3d36382961 100644 --- a/src/input.h +++ b/src/input.h @@ -21,14 +21,17 @@ #ifndef _INPUT_H_ #define _INPUT_H_ +#include "interface/window.h" + enum { INPUT_FLAG_WIDGET_PRESSED = (1 << 0), - // Related to dropdowns, set on flag 0x80 - INPUT_FLAG_1 = (1 << 1), + // The dropdown can stay open if the mouse is released, set on flag DROPDOWN_FLAG_STAY_OPEN + INPUT_FLAG_DROPDOWN_STAY_OPEN = (1 << 1), - // Related to dropdowns - INPUT_FLAG_2 = (1 << 2), + // The mouse has been released and the dropdown is still open + // INPUT_FLAG_DROPDOWN_STAY_OPEN is already set if this happens + INPUT_FLAG_DROPDOWN_MOUSE_UP = (1 << 2), INPUT_FLAG_TOOL_ACTIVE = (1 << 3), @@ -50,4 +53,6 @@ void game_handle_keyboard_input(); void store_mouse_input(int state); +void input_window_position_begin(rct_window *w, int widgetIndex, int x, int y); + #endif \ No newline at end of file diff --git a/src/interface/console.c b/src/interface/console.c new file mode 100644 index 0000000000..92a0708383 --- /dev/null +++ b/src/interface/console.c @@ -0,0 +1,968 @@ +#include +#include + +#include "../addresses.h" +#include "../drawing/drawing.h" +#include "../localisation/localisation.h" +#include "../platform/platform.h" +#include "../world/park.h" +#include "../util/sawyercoding.h" +#include "../config.h" +#include "../cursors.h" +#include "../game.h" +#include "../input.h" +#include "../network/twitch.h" +#include "../object.h" +#include "../world/scenery.h" +#include "../management/research.h" +#include "console.h" +#include "window.h" + +#define CONSOLE_BUFFER_SIZE 8192 +#define CONSOLE_BUFFER_2_SIZE 256 +#define CONSOLE_HISTORY_SIZE 64 +#define CONSOLE_INPUT_SIZE 256 + +bool gConsoleOpen = false; + +static bool _consoleInitialised = false; +static int _consoleLeft, _consoleTop, _consoleRight, _consoleBottom; +static int _lastMainViewportX, _lastMainViewportY; +static char _consoleBuffer[CONSOLE_BUFFER_SIZE] = { 0 }; +static char *_consoleBufferPointer = _consoleBuffer; +static char *_consoleViewBufferStart = _consoleBuffer; +static char _consoleCurrentLine[CONSOLE_INPUT_SIZE]; +static char *_consoleCurrentLinePointer = _consoleCurrentLine; +static int _consoleCaretTicks; +static char _consolePrintfBuffer[CONSOLE_BUFFER_2_SIZE]; +static char _consoleErrorBuffer[CONSOLE_BUFFER_2_SIZE]; +static int _consoleScrollPos = 0; + +static char _consoleHistory[CONSOLE_HISTORY_SIZE][CONSOLE_INPUT_SIZE]; +static int _consoleHistoryIndex = 0; +static int _consoleHistoryCount = 0; + +static void console_invalidate(); +static void console_write_prompt(); +static void console_update_scroll(); +static void console_clear_input(); +static void console_history_add(const char *src); +static void console_write_all_commands(); +static int console_parse_int(const char *src, bool *valid); +static double console_parse_double(const char *src, bool *valid); + +static int cc_variables(const char **argv, int argc); +static int cc_windows(const char **argv, int argc); +static int cc_help(const char **argv, int argc); + +#define SET_FLAG(variable, flag, value) {if (value) variable |= flag; else variable &= ~flag;} + +void console_open() +{ + gConsoleOpen = true; + _consoleScrollPos = 0; + console_refresh_caret(); + console_update_scroll(); + platform_start_text_input(_consoleCurrentLine, sizeof(_consoleCurrentLine)); +} + +void console_close() +{ + gConsoleOpen = false; + console_invalidate(); + platform_stop_text_input(); +} + +void console_toggle() +{ + if (gConsoleOpen) + console_close(); + else + console_open(); +} + +void console_init() +{ + _consoleInitialised = true; + console_writeline(OPENRCT2_NAME " " OPENRCT2_VERSION); + console_writeline(""); + console_write_prompt(); +} + +void console_update() +{ + if (!_consoleInitialised) + console_init(); + + _consoleLeft = 0; + _consoleTop = 0; + _consoleRight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); + _consoleBottom = 322; + + if (gConsoleOpen) { + console_invalidate(); + + // When scrolling the map, the console pixels get copied... therefore invalidate the screen + rct_window *mainWindow = window_get_main(); + if (mainWindow != NULL) { + rct_viewport *mainViewport = mainWindow->viewport; + if (mainViewport != NULL) { + if (_lastMainViewportX != mainViewport->view_x || _lastMainViewportY != mainViewport->view_y) { + _lastMainViewportX = mainViewport->view_x; + _lastMainViewportY = mainViewport->view_y; + + gfx_invalidate_screen(); + } + } + } + + // Remove unwated characters in console input + unsigned char *ch = (unsigned char*)_consoleCurrentLine; + while (*ch != 0) { + if (*ch < 32 || *ch > 126) + *ch = ' '; + ch++; + } + } + + // Flash the caret + _consoleCaretTicks = (_consoleCaretTicks + 1) % 30; +} + +void console_draw(rct_drawpixelinfo *dpi) +{ + if (!gConsoleOpen) + return; + int lines = 0; + int maxLines = ((_consoleBottom - 22 - _consoleTop) / 10) - 1; + char *ch = strchr(_consoleBuffer, 0); + while (ch > _consoleBuffer) { + ch--; + if (*ch == '\n') + lines++; + } + + // Set font + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = (gConfigInterface.console_small_font ? 0 : 224); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + // Background + gfx_fill_rect(dpi, _consoleLeft, _consoleTop, _consoleRight, _consoleBottom, 10); + + int x = _consoleLeft + 4; + int y = _consoleTop + 4; + + // Draw previous lines + char lineBuffer[1 + 256]; + ch = _consoleViewBufferStart; + int currentLine = 0; + int drawLines = 0; + while (*ch != 0) { + // Find line break or null terminator + char *nextLine = ch; + while (*nextLine != 0 && *nextLine != '\n') { + nextLine++; + } + + currentLine++; + if (currentLine < (lines - maxLines + 4) - _consoleScrollPos) { + if (*nextLine == '\n') { + ch = nextLine + 1; + x = _consoleLeft + 4; + //y += 10; + } + else { + break; + } + continue; + } + + if (drawLines >= maxLines) + break; + drawLines++; + + int lineLength = min(sizeof(lineBuffer) - 1, nextLine - ch); + strncpy(lineBuffer + 1, ch, lineLength); + lineBuffer[0] = FORMAT_GREEN; + lineBuffer[1 + lineLength] = 0; + + gfx_draw_string(dpi, lineBuffer, 255, x, y); + + x = gLastDrawStringX; + + if (*nextLine == '\n') { + ch = nextLine + 1; + x = _consoleLeft + 4; + y += 10; + } else { + break; + } + } + x = _consoleLeft + 4; + y = _consoleBottom - 15; + // Draw current line + strcpy(lineBuffer + 1, _consoleCurrentLine); + lineBuffer[0] = FORMAT_GREEN; + gfx_draw_string(dpi, lineBuffer, 255, x, y); + + // Draw caret + if (_consoleCaretTicks < 15) { + memcpy(lineBuffer, _consoleCurrentLine, gTextInputCursorPosition); + lineBuffer[gTextInputCursorPosition] = 0; + int caretX = x + gfx_get_string_width(lineBuffer); + int caretY = y + 10; + + gfx_fill_rect(dpi, caretX, caretY, caretX + 6, caretY + 1, FORMAT_GREEN); + } + gfx_fill_rect(dpi, _consoleLeft, _consoleBottom - 21, _consoleRight, _consoleBottom - 21, 14); + gfx_fill_rect(dpi, _consoleLeft, _consoleBottom - 20, _consoleRight, _consoleBottom - 20, 11); + + gfx_fill_rect(dpi, _consoleLeft, _consoleBottom - 1, _consoleRight, _consoleBottom - 1, 14); + gfx_fill_rect(dpi, _consoleLeft, _consoleBottom - 0, _consoleRight, _consoleBottom - 0, 12); +} + +void console_input(int c) +{ + switch (c) { + case SDL_SCANCODE_ESCAPE: + console_clear_input(); + console_refresh_caret(); + break; + case SDL_SCANCODE_RETURN: + if (_consoleCurrentLine[0] != 0) { + console_history_add(_consoleCurrentLine); + console_execute(_consoleCurrentLine); + console_write_prompt(); + console_clear_input(); + console_refresh_caret(); + } + break; + case SDL_SCANCODE_UP: + if (_consoleHistoryIndex > 0) { + _consoleHistoryIndex--; + memcpy(_consoleCurrentLine, _consoleHistory[_consoleHistoryIndex], 256); + } + gTextInputCursorPosition = strlen(_consoleCurrentLine); + gTextInputLength = gTextInputCursorPosition; + break; + case SDL_SCANCODE_DOWN: + if (_consoleHistoryIndex < _consoleHistoryCount - 1) { + _consoleHistoryIndex++; + memcpy(_consoleCurrentLine, _consoleHistory[_consoleHistoryIndex], 256); + gTextInputCursorPosition = strlen(_consoleCurrentLine); + gTextInputLength = gTextInputCursorPosition; + } else { + _consoleHistoryIndex = _consoleHistoryCount; + console_clear_input(); + } + break; + } +} + +static void console_invalidate() +{ + gfx_set_dirty_blocks(_consoleLeft, _consoleTop, _consoleRight, _consoleBottom); +} + +static void console_write_prompt() +{ + console_write("> "); +} + +void console_write(const char *src) +{ + int charactersRemainingInBuffer = CONSOLE_BUFFER_SIZE - (_consoleBufferPointer - _consoleBuffer) - 1; + int charactersToWrite = strlen(src); + int bufferShift = charactersToWrite - charactersRemainingInBuffer; + if (charactersToWrite > charactersRemainingInBuffer) { + memmove(_consoleBuffer, _consoleBuffer + bufferShift, CONSOLE_BUFFER_SIZE - bufferShift); + _consoleBufferPointer -= bufferShift; + } + strcpy(_consoleBufferPointer, src); + _consoleBufferPointer += charactersToWrite; + console_update_scroll(); +} + +void console_writeline(const char *src) +{ + console_write(src); + console_write("\n"); +} + +void console_writeline_error(const char *src) +{ + strcpy(_consoleErrorBuffer + 1, src); + _consoleErrorBuffer[0] = FORMAT_RED; + console_writeline(_consoleErrorBuffer); +} + +void console_writeline_warning(const char *src) +{ + strcpy(_consoleErrorBuffer + 1, src); + _consoleErrorBuffer[0] = FORMAT_YELLOW; + console_writeline(_consoleErrorBuffer); +} + +void console_printf(const char *format, ...) +{ + va_list list; + va_start(list, format); + + vsprintf(_consolePrintfBuffer, format, list); + console_writeline(_consolePrintfBuffer); +} + +int console_parse_int(const char *src, bool *valid) { + char *end; + int value; + value = strtol(src, &end, 10); *valid &= (*end == '\0'); + return value; +} + +double console_parse_double(const char *src, bool *valid) { + char *end; + double value; + value = strtod(src, &end); *valid &= (*end == '\0'); + return value; +} + +static void console_update_scroll() +{ + /*int lines = 0; + int maxLines = ((_consoleBottom - 22 - _consoleTop) / 10) - 1; + char *ch = strchr(_consoleBuffer, 0); + while (ch > _consoleBuffer && lines < maxLines) { + ch--; + if (*ch == '\n') + lines++; + } + + if (*ch == '\n') + ch++; + _consoleViewBufferStart = ch;*/ +} + +void console_scroll(int delta) +{ + int speed = 3; + int lines = 0; + int maxLines = ((_consoleBottom - 22 - _consoleTop) / 10) - 1; + char *ch = strchr(_consoleBuffer, 0); + while (ch > _consoleBuffer) { + ch--; + if (*ch == '\n') + lines++; + } + if (delta > 0 && _consoleScrollPos + 1 < (lines - maxLines + 4)) { + _consoleScrollPos = min(_consoleScrollPos + speed, (lines - maxLines + 4)); + } + else if (delta < 0 && _consoleScrollPos > 0) { + _consoleScrollPos = max(_consoleScrollPos - speed, 0); + } +} + +void console_clear() +{ + _consoleScrollPos = 0; + _consoleBuffer[0] = 0; + _consoleBufferPointer = _consoleBuffer; +} + +void console_clear_line() +{ + _consoleCurrentLine[0] = 0; + console_refresh_caret(); +} + +void console_refresh_caret() +{ + _consoleCaretTicks = 0; +} + +static void console_clear_input() +{ + _consoleCurrentLine[0] = 0; + gTextInputCursorPosition = 0; + gTextInputLength = 0; +} + +static void console_history_add(const char *src) +{ + if (_consoleHistoryCount >= CONSOLE_HISTORY_SIZE) { + for (int i = 0; i < _consoleHistoryCount - 1; i++) + memcpy(_consoleHistory[i], _consoleHistory[i + 1], CONSOLE_INPUT_SIZE); + _consoleHistoryCount--; + } + memcpy(_consoleHistory[_consoleHistoryCount++], src, CONSOLE_INPUT_SIZE); + _consoleHistoryIndex = _consoleHistoryCount; +} + +static int cc_clear(const char **argv, int argc) +{ + console_clear(); + return 0; +} + +static int cc_hide(const char **argv, int argc) +{ + console_close(); + return 0; +} + +static int cc_echo(const char **argv, int argc) +{ + if (argc > 0) + console_writeline(argv[0]); + return 0; +} + +static int cc_get(const char **argv, int argc) +{ + if (argc > 0) { + if (strcmp(argv[0], "park_rating") == 0) { + console_printf("park_rating %d", RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16)); + } + else if (strcmp(argv[0], "money") == 0) { + console_printf("money %d.%d0", DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32)) / 10, DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32)) % 10); + } + else if (strcmp(argv[0], "current_loan") == 0) { + console_printf("current_loan %d", RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) / 10); + } + else if (strcmp(argv[0], "max_loan") == 0) { + console_printf("max_loan %d", RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) / 10); + } + else if (strcmp(argv[0], "guest_initial_cash") == 0) { + console_printf("guest_initial_cash %d.%d0", RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) / 10, RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) % 10); + } + else if (strcmp(argv[0], "guest_initial_happiness") == 0) { + uint32 current_happiness = RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8); + for (int i = 15; i <= 99; i++) { + if (i == 99) { + console_printf("guest_initial_happiness %d%% (%d)", 15, RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8)); + } + else if (current_happiness == calculate_guest_initial_happiness(i)) { + console_printf("guest_initial_happiness %d%% (%d)", i, RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8)); + break; + } + } + } + else if (strcmp(argv[0], "guest_initial_hunger") == 0) { + console_printf("guest_initial_hunger %d%% (%d)", ((255 - RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8)) * 100) / 255, RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8)); + } + else if (strcmp(argv[0], "guest_initial_thirst") == 0) { + console_printf("guest_initial_thirst %d%% (%d)", ((255 - RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8)) * 100) / 255, RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8)); + } + else if (strcmp(argv[0], "guest_prefer_less_intense_rides") == 0) { + console_printf("guest_prefer_less_intense_rides %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_LESS_INTENSE_RIDES) != 0); + } + else if (strcmp(argv[0], "guest_prefer_more_intense_rides") == 0) { + console_printf("guest_prefer_more_intense_rides %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) != 0); + } + else if (strcmp(argv[0], "forbid_marketing_campagns") == 0) { + console_printf("forbid_marketing_campagns %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) != 0); + } + else if (strcmp(argv[0], "forbid_landscape_changes") == 0) { + console_printf("forbid_landscape_changes %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) != 0); + } + else if (strcmp(argv[0], "forbid_tree_removal") == 0) { + console_printf("forbid_tree_removal %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_TREE_REMOVAL) != 0); + } + else if (strcmp(argv[0], "forbid_high_construction") == 0) { + console_printf("forbid_high_construction %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION) != 0); + } + else if (strcmp(argv[0], "pay_for_rides") == 0) { + console_printf("pay_for_rides %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) != 0); + } + else if (strcmp(argv[0], "no_money") == 0) { + console_printf("no_money %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) != 0); + } + else if (strcmp(argv[0], "difficult_park_rating") == 0) { + console_printf("difficult_park_rating %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_DIFFICULT_PARK_RATING) != 0); + } + else if (strcmp(argv[0], "difficult_guest_generation") == 0) { + console_printf("difficult_guest_generation %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) != 0); + } + else if (strcmp(argv[0], "park_open") == 0) { + console_printf("park_open %d", (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) != 0); + } + else if (strcmp(argv[0], "land_rights_cost") == 0) { + console_printf("land_rights_cost %d.%d0", RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) / 10, RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) % 10); + } + else if (strcmp(argv[0], "construction_rights_cost") == 0) { + console_printf("construction_rights_cost %d.%d0", RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money32) / 10, RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money32) % 10); + } + else if (strcmp(argv[0], "climate") == 0) { + const char* climate_names[] = { "cool_and_wet", "warm", "hot_and_dry", "cold" }; + console_printf("climate %s (%d)", climate_names[RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, sint8)], RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, sint8)); + } + else if (strcmp(argv[0], "game_speed") == 0) { + console_printf("game_speed %d", gGameSpeed); + } + else if (strcmp(argv[0], "console_small_font") == 0) { + console_printf("console_small_font %d", gConfigInterface.console_small_font); + } + else if (strcmp(argv[0], "test_unfinished_tracks") == 0) { + console_printf("test_unfinished_tracks %d", gConfigGeneral.test_unfinished_tracks); + } + else if (strcmp(argv[0], "no_test_crashes") == 0) { + console_printf("no_test_crashes %d", gConfigGeneral.no_test_crashes); + } + else { + console_writeline_warning("Invalid variable."); + } + } + return 0; +} +static int cc_set(const char **argv, int argc) +{ + if (argc > 1) { + bool int_valid = true, double_valid = true; + + int int_val = console_parse_int(argv[1], &int_valid); + double double_val = console_parse_double(argv[1], &double_valid); + + if (strcmp(argv[0], "money") == 0 && double_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32) = ENCRYPT_MONEY(MONEY((int)double_val, ((int)(double_val * 100)) % 100)); + console_execute_silent("get money"); + } + else if (strcmp(argv[0], "current_loan") == 0 && int_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp(MONEY(int_val - (int_val % 1000), 0), MONEY(0, 0), RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32)); + console_execute_silent("get current_loan"); + } + else if (strcmp(argv[0], "max_loan") == 0 && int_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = clamp(MONEY(int_val - (int_val % 1000), 0), MONEY(0, 0), MONEY(5000000, 0)); + console_execute_silent("get max_loan"); + } + else if (strcmp(argv[0], "guest_initial_cash") == 0 && double_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) = clamp(MONEY((int)double_val, ((int)(double_val * 100)) % 100), MONEY(0, 0), MONEY(15000, 0)); + console_execute_silent("get guest_initial_cash"); + } + else if (strcmp(argv[0], "guest_initial_happiness") == 0 && int_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) = calculate_guest_initial_happiness((uint8)int_val); + console_execute_silent("get guest_initial_happiness"); + } + else if (strcmp(argv[0], "guest_initial_hunger") == 0 && int_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8) = (clamp(int_val, 1, 84) * 255 / 100 - 255) * -1; + console_execute_silent("get guest_initial_hunger"); + } + else if (strcmp(argv[0], "guest_initial_thirst") == 0 && int_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8) = (clamp(int_val, 1, 84) * 255 / 100 - 255) * -1; + console_execute_silent("get guest_initial_thirst"); + } + else if (strcmp(argv[0], "guest_prefer_less_intense_rides") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PREF_LESS_INTENSE_RIDES, int_val); + console_execute_silent("get guest_prefer_less_intense_rides"); + } + else if (strcmp(argv[0], "guest_prefer_more_intense_rides") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PREF_MORE_INTENSE_RIDES, int_val); + console_execute_silent("get guest_prefer_more_intense_rides"); + } + else if (strcmp(argv[0], "forbid_marketing_campagns") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_MARKETING_CAMPAIGN, int_val); + console_execute_silent("get forbid_marketing_campagns"); + } + else if (strcmp(argv[0], "forbid_landscape_changes") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_LANDSCAPE_CHANGES, int_val); + console_execute_silent("get forbid_landscape_changes"); + } + else if (strcmp(argv[0], "forbid_tree_removal") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_TREE_REMOVAL, int_val); + console_execute_silent("get forbid_tree_removal"); + } + else if (strcmp(argv[0], "forbid_high_construction") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_HIGH_CONSTRUCTION, int_val); + console_execute_silent("get forbid_high_construction"); + } + else if (strcmp(argv[0], "pay_for_rides") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PARK_FREE_ENTRY, int_val); + console_execute_silent("get pay_for_rides"); + } + else if (strcmp(argv[0], "no_money") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_NO_MONEY, int_val); + console_execute_silent("get no_money"); + } + else if (strcmp(argv[0], "difficult_park_rating") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_DIFFICULT_PARK_RATING, int_val); + console_execute_silent("get difficult_park_rating"); + } + else if (strcmp(argv[0], "difficult_guest_generation") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_DIFFICULT_GUEST_GENERATION, int_val); + console_execute_silent("get difficult_guest_generation"); + } + else if (strcmp(argv[0], "park_open") == 0 && int_valid) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PARK_OPEN, int_val); + console_execute_silent("get park_open"); + } + else if (strcmp(argv[0], "land_rights_cost") == 0 && double_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) = clamp(MONEY((int)double_val, ((int)(double_val * 100)) % 100), MONEY(0, 0), MONEY(15000, 0)); + console_execute_silent("get land_rights_cost"); + } + else if (strcmp(argv[0], "construction_rights_cost") == 0 && double_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16) = clamp(MONEY((int)double_val, ((int)(double_val * 100)) % 100), MONEY(0, 0), MONEY(15000, 0)); + console_execute_silent("get construction_rights_cost"); + } + else if (strcmp(argv[0], "climate") == 0) { + if (int_valid) { + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, sint8) = clamp(int_val, 0, 3); + } + else { + char* climate_names[] = { "cool_and_wet", "warm", "hot_and_dry", "cold" }; + for (int i = 0; i < 4; i++) { + if (strcmp(argv[1], climate_names[i]) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, sint8) = i; + break; + } + } + } + console_execute_silent("get climate"); + } + else if (strcmp(argv[0], "game_speed") == 0 && int_valid) { + gGameSpeed = clamp(int_val, 1, 8); + console_execute_silent("get game_speed"); + } + else if (strcmp(argv[0], "console_small_font") == 0 && int_valid) { + gConfigInterface.console_small_font = (int_val != 0); + config_save_default(); + console_execute_silent("get console_small_font"); + } + else if (strcmp(argv[0], "test_unfinished_tracks") == 0 && int_valid) { + gConfigGeneral.test_unfinished_tracks = (int_val != 0); + config_save_default(); + console_execute_silent("get test_unfinished_tracks"); + } + else if (strcmp(argv[0], "no_test_crashes") == 0 && int_valid) { + gConfigGeneral.no_test_crashes = (int_val != 0); + config_save_default(); + console_execute_silent("get no_test_crashes"); + } + else { + console_writeline_error("Invalid variable or value."); + } + + gfx_invalidate_screen(); + } + return 0; +} +static int cc_twitch(const char **argv, int argc) +{ +#ifdef DISABLE_TWITCH + console_writeline_error("OpenRCT2 build not compiled with Twitch integeration."); +#else + // TODO add some twitch commands +#endif + return 0; +} +static void editor_load_selected_objects_console() +{ + uint8 *selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry *installed_entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) == 0) + return; + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i != 0; i--, selection_flags++) { + if (*selection_flags & 1) { + uint8 entry_index, entry_type; + if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){ + int chunk_size; + if (!object_load(-1, installed_entry, &chunk_size)) { + log_error("Failed to load entry %.8s", installed_entry->name); + } + } + } + + installed_entry = object_get_next(installed_entry); + } +} + +static int cc_load_object(const char **argv, int argc) { + if (argc > 0) { + char path[260]; + + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), argv[0]); + // Require pointer to start of filename + char* last_char = path + strlen(path); + strcat(path, ".DAT\0"); + + rct_object_entry entry; + if (object_load_entry(path, &entry)) { + uint8 type = entry.flags & 0xF; + uint8 index; + + if (check_object_entry(&entry)) { + if (!find_object_in_entry_group(&entry, &type, &index)){ + + int entryGroupIndex = 0; + for (; entryGroupIndex < object_entry_group_counts[type]; entryGroupIndex++){ + if (object_entry_groups[type].chunks[entryGroupIndex] == (uint8*)-1){ + break; + } + } + + if (entryGroupIndex >= object_entry_group_counts[type]) { + console_writeline_error("Too many objects of that type."); + } + else { + // Load the obect + if (!object_load(entryGroupIndex, &entry, NULL)) { + console_writeline_error("Could not load object file."); + } + else { + reset_loaded_objects(); + if (type == OBJECT_TYPE_RIDE) { + // Automatically research the ride so it's supported by the game. + rct_ride_type *rideEntry; + int rideType; + + rideEntry = GET_RIDE_ENTRY(entryGroupIndex); + + for (int j = 0; j < 3; j++) { + rideType = rideEntry->ride_type[j]; + if (rideType != 255) + research_insert(true, 0x10000 | (rideType << 8) | entryGroupIndex, rideEntry->category[0]); + } + + gSilentResearch = true; + sub_684AC3(); + gSilentResearch = false; + } + else if (type == OBJECT_TYPE_SCENERY_SETS) { + rct_scenery_set_entry *scenerySetEntry; + + scenerySetEntry = g_scenerySetEntries[entryGroupIndex]; + + research_insert(true, entryGroupIndex, RESEARCH_CATEGORY_SCENERYSET); + + gSilentResearch = true; + sub_684AC3(); + gSilentResearch = false; + } + scenery_set_default_placement_configuration(); + window_new_ride_init_vars(); + + RCT2_GLOBAL(0x009DEB7C, uint16) = 0; + gfx_invalidate_screen(); + console_writeline("Object file loaded."); + } + } + } + else { + console_writeline_error("Object is already in scenario."); + } + } + else { + console_writeline_error("The object file was invalid."); + } + } + else { + console_writeline_error("Could not find the object file."); + } + } + + return 0; +} +static int cc_object_count(const char **argv, int argc) { + const char* object_type_names[] = { "Rides", "Small scenery", "Large scenery", "Walls", "Banners", "Paths", "Path Additions", "Scenery groups", "Park entrances", "Water" }; + for (int i = 0; i < 10; i++) { + + int entryGroupIndex = 0; + for (; entryGroupIndex < object_entry_group_counts[i]; entryGroupIndex++){ + if (object_entry_groups[i].chunks[entryGroupIndex] == (uint8*)-1){ + break; + } + } + console_printf("%s: %d/%d", object_type_names[i], entryGroupIndex, object_entry_group_counts[i]); + } + + return 0; +} +static int cc_open(const char **argv, int argc) { + if (argc > 0) { + if (strcmp(argv[0], "object_selection") == 0) { + // Only this window should be open for safety reasons + window_close_all(); + window_editor_object_selection_open(); + } else if (strcmp(argv[0], "inventions_list") == 0) { + window_editor_inventions_list_open(); + } else if (strcmp(argv[0], "options") == 0) { + window_options_open(); + } else if (strcmp(argv[0], "themes") == 0) { + window_themes_open(); + } + else { + console_writeline_error("Invalid window."); + } + } + return 0; +} + + +typedef int (*console_command_func)(const char **argv, int argc); +typedef struct { + char *command; + console_command_func func; + char *help; + char *usage; +} console_command; + +char* console_variable_table[] = { + "park_rating", + "money", + "current_loan", + "max_loan", + "guest_initial_cash", + "guest_initial_happiness", + "guest_initial_hunger", + "guest_initial_thirst", + "guest_prefer_less_intense_rides", + "guest_prefer_more_intense_rides", + "forbid_marketing_campagn", + "forbid_landscape_changes", + "forbid_tree_removal", + "forbid_high_construction", + "pay_for_rides", + "no_money", + "difficult_park_rating", + "difficult_guest_generation", + "land_rights_cost", + "construction_rights_cost", + "park_open", + "climate", + "game_speed", + "console_small_font", + "test_unfinished_tracks", + "no_test_crashes" +}; +char* console_window_table[] = { + "object_selection", + "inventions_list", + "options", + "themes" +}; + +console_command console_command_table[] = { + { "clear", cc_clear, "Clears the console.", "clear"}, + { "hide", cc_hide, "Hides the console.", "hide"}, + { "echo", cc_echo, "Echos the text to the console.", "echo " }, + { "help", cc_help, "Lists commands or info about a command.", "help [command]" }, + { "get", cc_get, "Gets the value of the specified variable.", "get " }, + { "set", cc_set, "Sets the variable to the specified value.", "set " }, + { "open", cc_open, "Opens the window with the give name.", "open ." }, + { "variables", cc_variables, "Lists all the variables that can be used with get and sometimes set.", "variables" }, + { "windows", cc_windows, "Lists all the windows that can be opened.", "windows" }, + { "load_object", cc_load_object, "Loads the object file into the scenario.\n" + "Loading a scenery group will not load its associated objects.\n" + "This is a safer method opposed to \"open object_selection\".", + "load_object " }, + { "object_count", cc_object_count, "Shows the number of objects of each type in the scenario.", "object_count" }, + { "twitch", cc_twitch, "Twitch API" } +}; + +static int cc_windows(const char **argv, int argc) { + for (int i = 0; i < countof(console_window_table); i++) + console_writeline(console_window_table[i]); + return 0; +} +static int cc_variables(const char **argv, int argc) +{ + for (int i = 0; i < countof(console_variable_table); i++) + console_writeline(console_variable_table[i]); + return 0; +} + +static int cc_help(const char **argv, int argc) +{ + if (argc > 0) { + for (int i = 0; i < countof(console_command_table); i++) { + if (strcmp(console_command_table[i].command, argv[0]) == 0) { + console_writeline(console_command_table[i].help); + console_printf("\nUsage: %s", console_command_table[i].usage); + } + } + } + else { + console_write_all_commands(); + } + return 0; +} + +static void console_write_all_commands() +{ + for (int i = 0; i < countof(console_command_table); i++) + console_writeline(console_command_table[i].command); +} + +void console_execute(const char *src) +{ + console_writeline(src); + + console_execute_silent(src); +} + +void console_execute_silent(const char *src) +{ + int argc = 0; + int argvCapacity = 8; + char **argv = malloc(argvCapacity * sizeof(char*)); + const char *start = src; + const char *end; + bool inQuotes = false; + do { + while (*start == ' ') + start++; + + if (*start == '"') { + inQuotes = true; + start++; + } + else { + inQuotes = false; + } + + end = start; + while (*end != 0) { + if (*end == ' ' && !inQuotes) + break; + if (*end == '"' && inQuotes) + break; + end++; + } + int length = end - start; + + if (length > 0) { + char *arg = malloc(length + 1); + memcpy(arg, start, length); + arg[length] = 0; + + if (argc >= argvCapacity) { + argvCapacity *= 2; + argv = realloc(argv, argvCapacity * sizeof(char*)); + } + argv[argc] = arg; + argc++; + } + + start = end; + } while (*end != 0); + + if (argc == 0) + return; + + bool validCommand = false; + for (int i = 0; i < countof(console_command_table); i++) { + if (strcmp(argv[0], console_command_table[i].command) == 0) { + console_command_table[i].func(argv + 1, argc - 1); + validCommand = true; + break; + } + } + + for (int i = 0; i < argc; i++) + free(argv[i]); + free(argv); + + if (!validCommand) { + char output[] = { FORMAT_RED, "Unknown command. Type help to list available commands." }; + console_writeline(output); + } +} \ No newline at end of file diff --git a/src/interface/console.h b/src/interface/console.h new file mode 100644 index 0000000000..3c11077edb --- /dev/null +++ b/src/interface/console.h @@ -0,0 +1,29 @@ +#ifndef _CONSOLE_H_ +#define _CONSOLE_H_ + +#include "../common.h" +#include "../drawing/drawing.h" + +extern bool gConsoleOpen; + +void console_open(); +void console_close(); +void console_toggle(); + +void console_update(); +void console_draw(rct_drawpixelinfo *dpi); + +void console_input(int c); +void console_write(const char *src); +void console_writeline(const char *src); +void console_writeline_error(const char *src); +void console_writeline_warning(const char *src); +void console_printf(const char *format, ...); +void console_execute(const char *src); +void console_execute_silent(const char *src); +void console_clear(); +void console_clear_line(); +void console_refresh_caret(); +void console_scroll(int delta); + +#endif \ No newline at end of file diff --git a/src/interface/keyboard_shortcut.c b/src/interface/keyboard_shortcut.c index bd0cfdeaf2..c2e65483c2 100644 --- a/src/interface/keyboard_shortcut.c +++ b/src/interface/keyboard_shortcut.c @@ -25,6 +25,7 @@ #include "keyboard_shortcut.h" #include "viewport.h" #include "window.h" +#include "widget.h" typedef void (*shortcut_action)(); @@ -50,7 +51,7 @@ void keyboard_shortcut_set(int key) gShortcutKeys[RCT2_GLOBAL(0x009DE511, uint8)] = key; window_close_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); window_invalidate_by_class(WC_KEYBOARD_SHORTCUT_LIST); - config_save(); + config_shortcut_keys_save(); } /** @@ -171,7 +172,45 @@ static void shortcut_rotate_view() static void shortcut_rotate_construction_object() { - RCT2_CALLPROC_EBPSAFE(0x006E4182); + rct_window *w; + + // Rotate scenery + w = window_find_by_class(WC_SCENERY); + if (w != NULL && !widget_is_disabled(w, 25) && w->widgets[25].type != WWT_EMPTY) { + window_event_mouse_up_call(w, 25); + return; + } + + // Rotate construction track piece + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && !widget_is_disabled(w, 32) && w->widgets[32].type != WWT_EMPTY) { + // Check if building a maze... + if (w->widgets[32].tooltip != 1761) { + window_event_mouse_up_call(w, 32); + return; + } + } + + // Rotate track design preview + w = window_find_by_class(WC_TRACK_DESIGN_LIST); + if (w != NULL && !widget_is_disabled(w, 5) && w->widgets[5].type != WWT_EMPTY) { + window_event_mouse_up_call(w, 5); + return; + } + + // Rotate track design placement + w = window_find_by_class(WC_TRACK_DESIGN_PLACE); + if (w != NULL && !widget_is_disabled(w, 3) && w->widgets[3].type != WWT_EMPTY) { + window_event_mouse_up_call(w, 3); + return; + } + + // Rotate park entrance + w = window_find_by_class(WC_MAP); + if (w != NULL && !widget_is_disabled(w, 20) && w->widgets[20].type != WWT_EMPTY) { + window_event_mouse_up_call(w, 20); + return; + } } static void shortcut_underground_view_toggle() @@ -308,14 +347,11 @@ static void shortcut_show_financial_information() static void shortcut_show_research_information() { - rct_window *window; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))) { - // Open new ride window - RCT2_CALLPROC_EBPSAFE(0x006B3CFF); - window = window_find_by_class(WC_CONSTRUCT_RIDE); - if (window != NULL) - window_event_mouse_up_call(window, 10); + if (gConfigInterface.toolbar_show_research) + window_research_open(); + else + window_new_ride_open_research(); } } @@ -386,7 +422,7 @@ static void shortcut_show_map() static void shortcut_screenshot() { - RCT2_CALLPROC_EBPSAFE(0x006E4034); // set screenshot countdown to 2 + RCT2_GLOBAL(RCT2_ADDRESS_SCREENSHOT_COUNTDOWN, uint8) = 2; } static void shortcut_reduce_game_speed() @@ -403,6 +439,9 @@ static void shortcut_open_cheat_window() { rct_window *window; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) != SCREEN_FLAGS_PLAYING) + return; + // Check if window is already open window = window_find_by_class(WC_CHEATS); if (window != NULL) { diff --git a/src/interface/screenshot.c b/src/interface/screenshot.c index cef28b0290..5aa010ca5a 100644 --- a/src/interface/screenshot.c +++ b/src/interface/screenshot.c @@ -25,10 +25,12 @@ #include "../drawing/drawing.h" #include "../game.h" #include "../localisation/localisation.h" -#include "../platform/osinterface.h" +#include "../openrct2.h" #include "../platform/platform.h" +#include "../util/util.h" #include "../windows/error.h" #include "screenshot.h" +#include "viewport.h" static const char *_screenshot_format_extension[] = { ".bmp", ".png" }; @@ -50,10 +52,10 @@ void screenshot_check() screenshotIndex = screenshot_dump(); if (screenshotIndex != -1) { - char *lang_3165 = (char*)0x009BC677; - sprintf(lang_3165, "SCR%d%s", screenshotIndex, _screenshot_format_extension[gGeneral_config.screenshot_format]); + rct_string_id stringId = 3165; + sprintf((char*)language_get_string(stringId), "SCR%d%s", screenshotIndex, _screenshot_format_extension[gConfigGeneral.screenshot_format]); - RCT2_GLOBAL(0x013CE952, uint16) = 3165; + RCT2_GLOBAL(0x013CE952, uint16) = stringId; // RCT2_GLOBAL(0x013CE952, uint16) = STR_SCR_BMP; // RCT2_GLOBAL(0x013CE952 + 2, uint16) = screenshotIndex; RCT2_GLOBAL(0x009A8C29, uint8) |= 1; @@ -71,11 +73,11 @@ void screenshot_check() static int screenshot_get_next_path(char *path, int format) { - char *screenshotPath = osinterface_get_orct2_homesubfolder("screenshot"); - if (!platform_ensure_directory_exists(screenshotPath)) { - free(screenshotPath); + char screenshotPath[MAX_PATH]; - fprintf(stderr, "Unable to save screenshots in OpenRCT2 screenshot directory.\n"); + platform_get_user_directory(screenshotPath, "screenshot"); + if (!platform_ensure_directory_exists(screenshotPath)) { + log_error("Unable to save screenshots in OpenRCT2 screenshot directory.\n"); return -1; } @@ -84,20 +86,20 @@ static int screenshot_get_next_path(char *path, int format) RCT2_GLOBAL(0x013CE952, uint16) = i; // Glue together path and filename - sprintf(path, "%s%cSCR%d%s", screenshotPath, osinterface_get_path_separator(), i, _screenshot_format_extension[format]); + sprintf(path, "%sSCR%d%s", screenshotPath, i, _screenshot_format_extension[format]); if (!platform_file_exists(path)) { return i; } } - free(screenshotPath); + log_error("You have too many saved screenshots.\n"); return -1; } int screenshot_dump() { - switch (gGeneral_config.screenshot_format) { + switch (gConfigGeneral.screenshot_format) { case SCREENSHOT_FORMAT_BMP: return screenshot_dump_bmp(); case SCREENSHOT_FORMAT_PNG: @@ -234,7 +236,7 @@ int screenshot_dump_png() { rct_drawpixelinfo *dpi = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); - int i, index, width, height, stride; + int i, index, width, height, padding; char path[MAX_PATH] = ""; unsigned int error; unsigned char r, g, b, a = 255; @@ -254,7 +256,8 @@ int screenshot_dump_png() // Get image size width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); - stride = (width + 3) & ~3; + + padding = dpi->pitch; for (i = 0; i < 256; i++) { b = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 0]; @@ -264,7 +267,24 @@ int screenshot_dump_png() lodepng_palette_add(&state.info_raw, r, g, b, a); } - error = lodepng_encode(&png, &pngSize, dpi->bits, stride, dpi->height, &state); + uint8* pixels = dpi->bits; + + if (padding > 0) { + pixels = malloc(width * height); + if (!pixels) { + return -1; + } + uint8* src = dpi->bits; + uint8* dst = pixels; + for (int y = height; y > 0; y--) { + for (int x = width; x > 0; x--) { + *dst++ = *src++; + } + src += padding; + } + } + + error = lodepng_encode(&png, &pngSize, pixels, width, height, &state); if (error) { log_error("Unable to save screenshot, %u: %s", lodepng_error_text(error)); index = -1; @@ -273,5 +293,270 @@ int screenshot_dump_png() } free(png); + if (pixels != dpi->bits) { + free(pixels); + } return index; +} + +bool screenshot_write_png(rct_drawpixelinfo *dpi, const char *path) +{ + unsigned int error; + unsigned char* png; + size_t pngSize; + LodePNGState state; + + lodepng_state_init(&state); + state.info_raw.colortype = LCT_PALETTE; + + // Get image size + int stride = (dpi->width + 3) & ~3; + + for (int i = 0; i < 256; i++) { + unsigned char r, g, b, a = 255; + + b = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 0]; + g = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 1]; + r = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 2]; + + lodepng_palette_add(&state.info_raw, r, g, b, a); + } + + error = lodepng_encode(&png, &pngSize, dpi->bits, stride, dpi->height, &state); + if (error != 0) { + free(png); + return false; + } else { + error = lodepng_save_file(png, pngSize, path); + if (error != 0) { + free(png); + return false; + } + } + + free(png); + return true; +} + +void screenshot_giant() +{ + int originalRotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + int originalZoom = 0; + + rct_window *mainWindow = window_get_main(); + if (mainWindow != NULL && mainWindow->viewport != NULL) + originalZoom = mainWindow->viewport->zoom; + + int rotation = originalRotation; + int zoom = originalZoom; + int mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16); + int resolutionWidth = (mapSize * 32 * 2) >> zoom; + int resolutionHeight = (mapSize * 32 * 1) >> zoom; + + resolutionWidth += 8; + resolutionHeight += 128; + + rct_viewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = resolutionWidth; + viewport.height = resolutionHeight; + viewport.view_width = viewport.width; + viewport.view_height = viewport.height; + viewport.var_11 = 0; + viewport.flags = 0; + + int centreX = (mapSize / 2) * 32 + 16; + int centreY = (mapSize / 2) * 32 + 16; + + int x, y; + int z = map_element_height(centreX, centreY) & 0xFFFF; + switch (rotation) { + case 0: + x = centreY - centreX; + y = ((centreX + centreY) / 2) - z; + break; + case 1: + x = -centreY - centreX; + y = ((-centreX + centreY) / 2) - z; + break; + case 2: + x = -centreY + centreX; + y = ((-centreX - centreY) / 2) - z; + break; + case 3: + x = centreY + centreX; + y = ((centreX - centreY) / 2) - z; + break; + } + + viewport.view_x = x - ((viewport.view_width << zoom) / 2); + viewport.view_y = y - ((viewport.view_height << zoom) / 2); + viewport.zoom = zoom; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) = rotation; + + // Ensure sprites appear regardless of rotation + reset_all_sprite_quadrant_placements(); + + rct_drawpixelinfo dpi; + dpi.x = 0; + dpi.y = 0; + dpi.width = resolutionWidth; + dpi.height = resolutionHeight; + dpi.pitch = 0; + dpi.zoom_level = 0; + dpi.bits = malloc(dpi.width * dpi.height); + + viewport_render(&dpi, &viewport, 0, 0, viewport.width, viewport.height); + + // Get a free screenshot path + char path[MAX_PATH]; + int index; + if ((index = screenshot_get_next_path(path, SCREENSHOT_FORMAT_PNG)) == -1) { + log_error("Giant screenshot failed, unable to find a suitable destination path."); + window_error_open(STR_SCREENSHOT_FAILED, -1); + return; + } + + screenshot_write_png(&dpi, path); + + free(dpi.bits); + + // Show user that screenshot saved successfully + rct_string_id stringId = 3165; + strcpy((char*)language_get_string(stringId), path_get_filename(path)); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = stringId; + window_error_open(STR_SCREENSHOT_SAVED_AS, -1); +} + +int cmdline_for_screenshot(const char **argv, int argc) +{ + bool giantScreenshot = argc == 5 && _stricmp(argv[2], "giant") == 0; + if (argc != 4 && argc != 8 && !giantScreenshot) { + printf("Usage: openrct2 screenshot [ ]\n"); + printf("Usage: openrct2 screenshot giant \n"); + return -1; + } + + bool customLocation = false; + bool centreMapX = false; + bool centreMapY = false; + int resolutionWidth, resolutionHeight, customX, customY, customZoom, customRotation; + + const char *inputPath = argv[0]; + const char *outputPath = argv[1]; + if (giantScreenshot) { + resolutionWidth = 0; + resolutionHeight = 0; + customLocation = true; + centreMapX = true; + centreMapY = true; + customZoom = atoi(argv[3]); + customRotation = atoi(argv[4]) & 3; + } else { + resolutionWidth = atoi(argv[2]); + resolutionHeight = atoi(argv[3]); + if (argc == 8) { + customLocation = true; + if (argv[4][0] == 'c') + centreMapX = true; + else + customX = atoi(argv[4]); + if (argv[5][0] == 'c') + centreMapY = true; + else + customY = atoi(argv[5]); + + customZoom = atoi(argv[6]); + customRotation = atoi(argv[7]) & 3; + } + } + + gOpenRCT2Headless = true; + if (openrct2_initialise()) { + rct2_open_file(inputPath); + + RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; + + int mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16); + if (resolutionWidth == 0 || resolutionHeight == 0) { + resolutionWidth = (mapSize * 32 * 2) >> customZoom; + resolutionHeight = (mapSize * 32 * 1) >> customZoom; + + resolutionWidth += 8; + resolutionHeight += 128; + } + + rct_viewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = resolutionWidth; + viewport.height = resolutionHeight; + viewport.view_width = viewport.width; + viewport.view_height = viewport.height; + viewport.var_11 = 0; + viewport.flags = 0; + + if (customLocation) { + if (centreMapX) + customX = (mapSize / 2) * 32 + 16; + if (centreMapY) + customY = (mapSize / 2) * 32 + 16; + + int x, y; + int z = map_element_height(customX, customY) & 0xFFFF; + switch (customRotation) { + case 0: + x = customY - customX; + y = ((customX + customY) / 2) - z; + break; + case 1: + x = -customY - customX; + y = ((-customX + customY) / 2) - z; + break; + case 2: + x = -customY + customX; + y = ((-customX - customY) / 2) - z; + break; + case 3: + x = customY + customX; + y = ((customX - customY) / 2) - z; + break; + } + + viewport.view_x = x - ((viewport.view_width << customZoom) / 2); + viewport.view_y = y - ((viewport.view_height << customZoom) / 2); + viewport.zoom = customZoom; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) = customRotation; + } else { + viewport.view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16) - (viewport.view_width / 2); + viewport.view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16) - (viewport.view_height / 2); + viewport.zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) & 0xFF; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) >> 8; + } + + // Ensure sprites appear regardless of rotation + reset_all_sprite_quadrant_placements(); + + rct_drawpixelinfo dpi; + dpi.x = 0; + dpi.y = 0; + dpi.width = resolutionWidth; + dpi.height = resolutionHeight; + dpi.pitch = 0; + dpi.zoom_level = 0; + dpi.bits = malloc(dpi.width * dpi.height); + + viewport_render(&dpi, &viewport, 0, 0, viewport.width, viewport.height); + + screenshot_write_png(&dpi, outputPath); + + free(dpi.bits); + } + openrct2_dispose(); + return 1; } \ No newline at end of file diff --git a/src/interface/screenshot.h b/src/interface/screenshot.h index 2515ebe79d..0672a135bb 100644 --- a/src/interface/screenshot.h +++ b/src/interface/screenshot.h @@ -24,4 +24,7 @@ void screenshot_check(); int screenshot_dump(); +void screenshot_giant(); +int cmdline_for_screenshot(const char **argv, int argc); + #endif \ No newline at end of file diff --git a/src/interface/themes.c b/src/interface/themes.c new file mode 100644 index 0000000000..dc22390267 --- /dev/null +++ b/src/interface/themes.c @@ -0,0 +1,241 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Peter Hill +* 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 "../localisation/string_ids.h" +#include "window.h" +#include "themes.h" + +#define COLOURS_1(c0) 1, { { (c0), 0, 0, 0, 0, 0 } } +#define COLOURS_2(c0, c1) 2, { { (c0), (c1), 0, 0, 0, 0 } } +#define COLOURS_3(c0, c1, c2) 3, { { (c0), (c1), (c2), 0, 0, 0 } } +#define COLOURS_4(c0, c1, c2, c3) 4, { { (c0), (c1), (c2), (c3), 0, 0 } } +#define COLOURS_5(c0, c1, c2, c3, c4) 5, { { (c0), (c1), (c2), (c3), (c4), 0 } } +#define COLOURS_6(c0, c1, c2, c3, c4, c5) 6, { { (c0), (c1), (c2), (c3), (c4), (c5) } } + +#define TWINDOW(window_class, window_name, window_string_id, theme) { window_class, window_name, window_string_id, theme } + +theme_window_definition gThemeWindowDefinitions[] = { + /* Window Class ini section name stringid window defaults */ + { WC_TOP_TOOLBAR, "top_toolbar", 5245, COLOURS_4(7, 12, 24, 1) }, + { WC_BOTTOM_TOOLBAR, "bottom_toolbar", 5246, COLOURS_4(140, 140, 0, 14) }, + { WC_RIDE, "ride", 5203, COLOURS_3(1, 26, 1) }, + { WC_RIDE_CONSTRUCTION, "ride_construction", 5199, COLOURS_3(24, 24, 24) }, + { WC_RIDE_LIST, "ride_list", 5204, COLOURS_3(1, 26, 26) }, + { WC_SAVE_PROMPT, "save_prompt", 5223, COLOURS_1(154) }, + { WC_CONSTRUCT_RIDE, "new_ride", 5201, COLOURS_3(24, 26, 26) }, + { WC_DEMOLISH_RIDE_PROMPT, "demolish_ride_prompt", 5224, COLOURS_1(154) }, + { WC_SCENERY, "scenery", 5197, COLOURS_3(24, 12, 12) }, + { WC_OPTIONS, "options", 5219, COLOURS_3(7, 7, 7) }, + { WC_FOOTPATH, "footpath", 5198, COLOURS_3(24, 24, 24) }, + { WC_LAND, "land", 5193, COLOURS_3(24, 24, 24) }, + { WC_WATER, "water", 5194, COLOURS_3(24, 24, 24) }, + { WC_PEEP, "guest", 5205, COLOURS_3(1, 15, 15) }, + { WC_GUEST_LIST, "guest_list", 5206, COLOURS_3(1, 15, 15) }, + { WC_STAFF_LIST, "staff_list", 5208, COLOURS_3(1, 4, 4) }, + { WC_FIRE_PROMPT, "staff_fire_prompt", 5225, COLOURS_1(154) }, + { WC_PARK_INFORMATION, "park_information", 5253, COLOURS_3(1, 19, 19) }, + { WC_FINANCES, "finances", 5187, COLOURS_3(1, 19, 19) }, + { WC_TITLE_MENU, "title_menu", 5249, COLOURS_3(140, 140, 140) }, + { WC_TITLE_EXIT, "title_exit", 5250, COLOURS_3(140, 140, 140) }, + { WC_RECENT_NEWS, "recent_news", 5192, COLOURS_3(1, 1, 0) }, + { WC_SCENARIO_SELECT, "scenario_select", 5252, COLOURS_3(1, 26, 26) }, + { WC_TRACK_DESIGN_LIST, "track_design_list", 5202, COLOURS_3(26, 26, 26) }, + { WC_TRACK_DESIGN_PLACE, "track_design_place", 5200, COLOURS_3(24, 24, 24) }, + { WC_NEW_CAMPAIGN, "new_campaign", 5188, COLOURS_3(19, 19, 19) }, + { WC_KEYBOARD_SHORTCUT_LIST, "keyboard_shortcuts", 5220, COLOURS_3(7, 7, 7) }, + { WC_CHANGE_KEYBOARD_SHORTCUT, "change_keyboard_shortcut", 5221, COLOURS_3(7, 7, 7) }, + { WC_MAP, "map", 5190, COLOURS_2(12, 24) }, + { WC_BANNER, "banner", 5209, COLOURS_3(24, 24, 24) }, + { WC_EDITOR_OBJECT_SELECTION, "editor_object_selection", 5210, COLOURS_3(4, 1, 1) }, + { WC_EDITOR_INVENTION_LIST, "editor_invention_list", 5211, COLOURS_3(4, 1, 1) }, + { WC_EDITOR_SCENARIO_OPTIONS, "editor_scenario_options", 5212, COLOURS_3(4, 1, 1) }, + { WC_EDTIOR_OBJECTIVE_OPTIONS, "editor_objection_options", 5213, COLOURS_3(4, 1, 1) }, + { WC_MANAGE_TRACK_DESIGN, "manage_track_design", 5215, COLOURS_3(1, 1, 1) }, + { WC_TRACK_DELETE_PROMPT, "track_delete_prompt", 5226, COLOURS_3(26, 26, 26) }, + { WC_INSTALL_TRACK, "install_track", 5216, COLOURS_3(26, 26, 26) }, + { WC_CLEAR_SCENERY, "clear_scenery", 5195, COLOURS_3(24, 24, 24) }, + { WC_CHEATS, "cheats", 5217, COLOURS_3(1, 19, 19) }, + { WC_RESEARCH, "research", 5189, COLOURS_3(1, 19, 19) }, + { WC_VIEWPORT, "viewport", 5191, COLOURS_3(24, 24, 24) }, + { WC_MAPGEN, "map_generation", 5214, COLOURS_3(12, 24, 24) }, + { WC_LOADSAVE, "loadsave", 5222, COLOURS_3(7, 7, 7) }, + { WC_LOADSAVE_OVERWRITE_PROMPT, "loadsave_overwrite_prompt", 5227, COLOURS_1(154) }, + { WC_TITLE_OPTIONS, "title_options", 5251, COLOURS_3(140, 140, 140) }, + { WC_LAND_RIGHTS, "land_rights", 5196, COLOURS_3(19, 19, 19) }, + { WC_THEMES, "themes", 5218, COLOURS_3(1, 12, 12) }, + { WC_STAFF, "staff", 5207, COLOURS_3(1, 4, 4) }, + { WC_EDITOR_TRACK_BOTTOM_TOOLBAR, "editor_track_bottom_toolbar", 5247, COLOURS_3(135, 135, 135) }, + { WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR, "editor_scenario_bottom_toolbar", 5248, COLOURS_3(150, 150, 141) }, +}; + +#define COLOURS_RCT1(c0, c1, c2, c3, c4, c5) { { (c0), (c1), (c2), (c3), (c4), (c5) } } + +theme_window_preset gThemeWindowsRCT1[] = { + { WC_TOP_TOOLBAR, COLOURS_RCT1(1, 1, 1, 1, 0, 0) }, + { WC_BOTTOM_TOOLBAR, COLOURS_RCT1(129, 129, 0, 18, 0, 0) }, + { WC_RIDE, COLOURS_RCT1(26, 1, 11, 0, 0, 0) }, + { WC_RIDE_LIST, COLOURS_RCT1(26, 1, 1, 0, 0, 0) }, + { WC_CONSTRUCT_RIDE, COLOURS_RCT1(26, 1, 1, 0, 0, 0) }, + { WC_PEEP, COLOURS_RCT1(22, 26, 26, 0, 0, 0) }, + { WC_GUEST_LIST, COLOURS_RCT1(22, 26, 26, 0, 0, 0) }, + { WC_STAFF_LIST, COLOURS_RCT1(12, 4, 4, 0, 0, 0) }, + { WC_FINANCES, COLOURS_RCT1(4, 1, 1, 0, 0, 0) }, + { WC_TITLE_MENU, COLOURS_RCT1(129, 129, 129, 0, 0, 0) }, + { WC_TITLE_EXIT, COLOURS_RCT1(129, 129, 129, 0, 0, 0) }, + { WC_NEW_CAMPAIGN, COLOURS_RCT1(4, 4, 1, 0, 0, 0) }, + { WC_TITLE_OPTIONS, COLOURS_RCT1(129, 129, 129, 0, 0, 0) }, + { WC_STAFF, COLOURS_RCT1(12, 4, 4, 0, 0, 0) }, + + + { 0xFF, { 0, 0, 0, 0, 0, 0 } } // End +}; + +uint16 gCurrentTheme = 0; +uint32 gNumThemeWindows = sizeof(gThemeWindowDefinitions) / sizeof(theme_window_definition); + + +theme_preset* theme_get_preset() +{ + return &gConfigThemes.presets[gCurrentTheme]; +} + +theme_window_definition* theme_window_definition_get_by_class(rct_windowclass classification) +{ + for (int i = 0; i < (int)gNumThemeWindows; i++) { + if (gThemeWindowDefinitions[i].classification == classification) { + return &gThemeWindowDefinitions[i]; + } + } + return NULL; +} + +theme_window* theme_window_get_by_class(rct_windowclass classification) +{ + for (int i = 0; i < (int)gNumThemeWindows; i++) { + if (gThemeWindowDefinitions[i].classification == classification) { + return &gConfigThemes.presets[gCurrentTheme].windows[i]; + } + } + return NULL; +} + +void colour_scheme_update(rct_window *window) +{ + theme_window* theme = theme_window_get_by_class(window->classification); + + bool transparent = false; + for (int i = 0; i < 6; i++) { + window->colours[i] = theme->colours[i]; + if (theme->colours[i] & 0x80) { + transparent = true; + } + } + // Some windows need to be transparent even if the colours aren't. + // There doesn't seem to be any side-effects for all windows being transparent + window->flags |= WF_TRANSPARENT; +} + +void colour_scheme_update_by_class(rct_window *window, rct_windowclass classification) +{ + theme_window* theme = theme_window_get_by_class(classification); + + bool transparent = false; + for (int i = 0; i < 6; i++) { + window->colours[i] = theme->colours[i]; + if (theme->colours[i] & 0x80) { + transparent = true; + } + } + // Some windows need to be transparent even if the colours aren't. + // There doesn't seem to be any side-effects for all windows being transparent + window->flags |= WF_TRANSPARENT; +} + +void theme_change_preset(int preset) +{ + if (preset >= 0 && preset < gConfigThemes.num_presets) { + switch (preset) { + case 0: + gConfigInterface.current_theme_preset = "*RCT2"; + break; + case 1: + gConfigInterface.current_theme_preset = "*RCT1"; + break; + default: + gConfigInterface.current_theme_preset = gConfigThemes.presets[preset].name; + break; + } + gCurrentTheme = preset; + } + window_invalidate_all(); +} + +void theme_create_preset(int duplicate, const char *name) +{ + int preset = gConfigThemes.num_presets; + gConfigThemes.num_presets++; + gConfigThemes.presets = realloc(gConfigThemes.presets, sizeof(theme_preset) * gConfigThemes.num_presets); + strcpy(gConfigThemes.presets[preset].name, name); + gConfigThemes.presets[preset].windows = malloc(sizeof(theme_window) * gNumThemeWindows); + for (int i = 0; i < (int)gNumThemeWindows; i++) { + gConfigThemes.presets[preset].windows[i] = gConfigThemes.presets[duplicate].windows[i]; + } + themes_save_preset(preset); + theme_change_preset(preset); +} + +void theme_delete_preset(int preset) +{ + if (preset >= 2) { + utf8 path[MAX_PATH]; + platform_get_user_directory(path, "themes"); + strcat(path, gConfigThemes.presets[preset].name); + strcat(path, ".ini"); + platform_file_delete(path); + + free(gConfigThemes.presets[preset].windows); + + for (int i = preset; i < gConfigThemes.num_presets - 1; i++) { + gConfigThemes.presets[i] = gConfigThemes.presets[i + 1]; + } + gConfigThemes.num_presets--; + theme_change_preset(0); + } +} + +void theme_rename_preset(int preset, const char *newName) +{ + if (preset >= 2) { + utf8 src[MAX_PATH], dest[MAX_PATH]; + platform_get_user_directory(src, "themes"); + platform_get_user_directory(dest, "themes"); + strcat(src, gConfigThemes.presets[preset].name); + strcat(dest, newName); + strcat(src, ".ini"); + strcat(dest, ".ini"); + platform_file_move(src, dest); + + strcpy(gConfigThemes.presets[gCurrentTheme].name, newName); + + if (preset == gCurrentTheme) { + gConfigInterface.current_theme_preset = gConfigThemes.presets[gCurrentTheme].name; + } + } +} diff --git a/src/interface/themes.h b/src/interface/themes.h new file mode 100644 index 0000000000..4ca788aade --- /dev/null +++ b/src/interface/themes.h @@ -0,0 +1,64 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost +* 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 _COLOUR_SCHEMES_H_ +#define _COLOUR_SCHEMES_H_ + +#include "../common.h" +#include "window.h" +#include "../config.h" + +typedef struct { + rct_windowclass classification; + char *section_name; + rct_string_id name; + uint8 num_colours; + theme_window window; +} theme_window_definition; + +typedef struct { + rct_windowclass classification; + theme_window window; +} theme_window_preset; + +// The definitions for window themes as well as the RCT2 preset +extern theme_window_definition gThemeWindowDefinitions[]; +// The preset for RCT1 window themes +extern theme_window_preset gThemeWindowsRCT1[]; + +// The index of the current theme +extern uint16 gCurrentTheme; +// The number of theme-able windows +extern uint32 gNumThemeWindows; + +theme_preset* theme_get_preset(); +theme_window_definition* theme_window_definition_get_by_class(rct_windowclass classification); +theme_window* theme_window_get_by_class(rct_windowclass classification); + +void colour_scheme_update(rct_window *window); +void colour_scheme_update_by_class(rct_window *window, rct_windowclass classification); + +void theme_change_preset(int preset); +void theme_create_preset(int duplicate, const char *name); +void theme_delete_preset(int preset); +void theme_rename_preset(int preset, const char *newName); + + +#endif \ No newline at end of file diff --git a/src/interface/viewport.c b/src/interface/viewport.c index 8903cd157c..eaa10bc927 100644 --- a/src/interface/viewport.c +++ b/src/interface/viewport.c @@ -1,9 +1,9 @@ /***************************************************************************** * 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 @@ -25,6 +25,8 @@ #include "../sprites.h" #include "../world/map.h" #include "../world/sprite.h" +#include "../world/banner.h" +#include "../world/scenery.h" #include "viewport.h" #include "window.h" @@ -43,19 +45,34 @@ struct paint_struct{ uint32 var_04; uint16 attached_x; // 0x08 uint16 attached_y; // 0x0A - uint8 var_0C; - uint8 pad_0D; - paint_struct* next_attached_ps; //0x0E - uint8 pad_12[2]; + union { + struct { + uint8 var_0C; + uint8 pad_0D; + paint_struct* next_attached_ps; //0x0E + uint16 pad_12; + }; + struct { + uint16 some_x; // 0x0C + uint16 some_y; // 0x0E + uint16 other_x; // 0x10 + uint16 other_y; // 0x12 + }; + }; uint16 x; // 0x14 uint16 y; // 0x16 - uint8 pad_18[2]; + uint16 var_18; uint8 var_1A; - uint8 pad_1B; + uint8 var_1B; paint_struct* attached_ps; //0x1C paint_struct* var_20; paint_struct* var_24; uint8 sprite_type; //0x28 + uint8 var_29; + uint16 pad_2A; + uint16 map_x; // 0x2C + uint16 map_y; // 0x2E + rct_map_element *mapElement; // 0x30 }; /** @@ -71,7 +88,7 @@ void viewport_init_all() // Palette from sprites? d = 0; for (i = 4915; i < 4947; i++) { - g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[i]); + g1_element = &g1Elements[i]; *((int*)(0x0141FC44 + d)) = *((int*)(&g1_element->offset[0xF5])); *((int*)(0x0141FC48 + d)) = *((int*)(&g1_element->offset[0xF9])); *((int*)(0x0141FD44 + d)) = *((int*)(&g1_element->offset[0xFD])); @@ -95,7 +112,7 @@ void viewport_init_all() RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16) = -1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, sint16) = 0; RCT2_GLOBAL(0x009DEA50, sint16) = -1; - RCT2_CALLPROC_EBPSAFE(0x006EE3C3); + textinput_cancel(); format_string((char*)0x0141FA44, STR_CANCEL, NULL); format_string((char*)0x0141F944, STR_OK, NULL); } @@ -106,7 +123,7 @@ void viewport_init_all() * z : cx * out_x : ax * out_y : bx - * Converts between 3d point of a sprite to 2d coordinates for centering on that sprite + * Converts between 3d point of a sprite to 2d coordinates for centering on that sprite */ void center_2d_coordinates(int x, int y, int z, int* out_x, int* out_y, rct_viewport* viewport){ int start_x = x; @@ -130,8 +147,17 @@ void center_2d_coordinates(int x, int y, int z, int* out_x, int* out_y, rct_view break; } - *out_x = x - viewport->view_width/2; - *out_y = y - viewport->view_height/2; + // If the start location was invalid + // propagate the invalid location to the output. + // This fixes a bug that caused the game to enter an infinite loop. + if (start_x == (sint16)0x8000){ + *out_x = (sint16)0x8000; + *out_y = 0; + return; + } + + *out_x = x - viewport->view_width / 2; + *out_y = y - viewport->view_height / 2; } /** @@ -174,7 +200,7 @@ void viewport_create(rct_window *w, int x, int y, int width, int height, int zoo viewport->zoom = zoom; viewport->flags = 0; - if (gGeneral_config.always_show_gridlines) + if (gConfigGeneral.always_show_gridlines) viewport->flags |= VIEWPORT_FLAG_GRIDLINES; w->viewport = viewport; @@ -198,14 +224,10 @@ void viewport_create(rct_window *w, int x, int y, int width, int height, int zoo viewport->view_y = view_y; viewport_update_pointers(); - - //x &= 0xFFFF; - //y &= 0xFFFF; - //RCT2_CALLPROC_X(0x006EB009, (y << 16) | x, (height << 16) | width, zoom, edx, (int)w, 0, 0); } /** - * + * * rct2: 0x006EE510 */ void viewport_update_pointers() @@ -221,47 +243,35 @@ void viewport_update_pointers() *vp = NULL; } -void sub_689174(sint16* x, sint16* y, sint16 *z, uint8 curr_rotation){ - //RCT2_CALLFUNC_X(0x00689174, (int*)&x, (int*)&y, (int*)&z, &curr_rotation, (int*)&window, (int*)&viewport, &ebp); - +/** + * edx is assumed to be (and always is) the current rotation, so it is not needed as parameter. + * rct2: 0x00689174 + */ +void sub_689174(sint16* x, sint16* y, sint16 *z) +{ sint16 start_x = *x; sint16 start_y = *y; sint16 height = 0; - switch (curr_rotation){ - case 0: - for (int i = 0; i < 6; ++i){ - *x = start_y - start_x / 2 + height; - *y = start_y + start_x / 2 + height; + rct_xy16 pos; + for (int i = 0; i < 6; i++) { + pos = viewport_coord_to_map_coord(start_x, start_y, height); + height = map_element_height((0xFFFF) & pos.x, (0xFFFF) & pos.y); - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); + // HACK: This is to prevent the x and y values being set to values outside + // of the map. This can happen when the height is larger than the map size. + sint16 max = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, sint16); + if (pos.x > max && pos.y > max) { + int x_corr[] = { -1, 1, 1, -1 }; + int y_corr[] = { -1, -1, 1, 1 }; + uint32 rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + pos.x += x_corr[rotation] * height; + pos.y += y_corr[rotation] * height; } - break; - case 1: - for (int i = 0; i < 6; ++i){ - *x = -start_y - start_x / 2 - height; - *y = start_y - start_x / 2 + height; - - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); - } - break; - case 2: - for (int i = 0; i < 6; ++i){ - *x = -start_y + start_x / 2 - height; - *y = -start_y - start_x / 2 - height; - - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); - } - break; - case 3: - for (int i = 0; i < 6; ++i){ - *x = start_x / 2 + start_y + height; - *y = start_x / 2 - start_y - height; - - height = map_element_height((0xFFFF) & *x, (0xFFFF) & *y); - } - break; } + + *x = pos.x; + *y = pos.y; *z = height; } @@ -298,13 +308,12 @@ void sub_689174(sint16* x, sint16* y, sint16 *z, uint8 curr_rotation){ // //} -void sub_6E7F34(rct_window* w, rct_viewport* viewport){ - //RCT2_CALLPROC_X(0x6E7F34, 0, 0, 0, 0, (int)viewport, (int)w, 0); +void sub_6E7F34(rct_window* w, rct_viewport* viewport, sint16 x_diff, sint16 y_diff){ rct_window* orignal_w = w; int left = 0, right = 0, top = 0, bottom = 0; for (; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++){ - if (!w->flags&WF_TRANSPARENT) continue; + if (!(w->flags & WF_TRANSPARENT)) continue; if (w->viewport == viewport) continue; if (viewport->x + viewport->width <= w->x)continue; @@ -318,11 +327,11 @@ void sub_6E7F34(rct_window* w, rct_viewport* viewport){ top = w->y; bottom = w->y + w->height; - if (left >= viewport->x)left = viewport->x; - if (right >= viewport->x + viewport->width) right = viewport->x + viewport->width; + if (left < viewport->x)left = viewport->x; + if (right > viewport->x + viewport->width) right = viewport->x + viewport->width; - if (top >= viewport->y)top = viewport->y; - if (bottom >= viewport->y + viewport->height) bottom = viewport->y + viewport->height; + if (top < viewport->y)top = viewport->y; + if (bottom > viewport->y + viewport->height) bottom = viewport->y + viewport->height; if (left >= right) continue; if (top >= bottom) continue; @@ -331,22 +340,23 @@ void sub_6E7F34(rct_window* w, rct_viewport* viewport){ } w = orignal_w; - RCT2_CALLPROC_X(0x6E7FF3, 0, 0, 0, right, (int)viewport, (int)w, bottom); + RCT2_CALLPROC_X(0x6E7FF3, 0, 0, 0, x_diff, (int)viewport, (int)w, y_diff); } -/* There is a bug in this. */ void sub_6E7DE1(sint16 x, sint16 y, rct_window* w, rct_viewport* viewport){ - //RCT2_CALLPROC_X(0x6E7DE1, x, y, 0, 0, w, viewport, 0); - //return; uint8 zoom = (1 << viewport->zoom); - sint16 previous_x = viewport->view_x / zoom; - sint16 previous_y = viewport->view_y / zoom; + // Note: do not do the subtraction and then divide! + // Note: Due to arithmatic shift != /zoom a shift will have to be used + // hopefully when 0x006E7FF3 is finished this can be converted to /zoom. + sint16 x_diff = (viewport->view_x >> viewport->zoom) - (x >> viewport->zoom); + sint16 y_diff = (viewport->view_y >> viewport->zoom) - (y >> viewport->zoom); viewport->view_x = x; viewport->view_y = y; - if (((x / zoom) == previous_x) && ((y / zoom) == previous_y)) return; + // If no change in viewing area + if ((!x_diff) && (!y_diff))return; if (w->flags & WF_7){ int left = max(viewport->x, 0); @@ -378,7 +388,7 @@ void sub_6E7DE1(sint16 x, sint16 y, rct_window* w, rct_viewport* viewport){ } if (viewport->width <= 0){ - memcpy( viewport, &view_copy,sizeof(rct_viewport)); + memcpy(viewport, &view_copy, sizeof(rct_viewport)); return; } @@ -400,21 +410,39 @@ void sub_6E7DE1(sint16 x, sint16 y, rct_window* w, rct_viewport* viewport){ return; } - //sub_6E7F34(w, viewport); - //RCT2_CALLPROC_X(0x6E7F34, 0, 0, 0, 0, (int)viewport, (int)w, 0); + sub_6E7F34(w, viewport, x_diff, y_diff); memcpy(viewport, &view_copy, sizeof(rct_viewport)); } +//rct2: 0x006E7A15 +void viewport_set_underground_flag(int underground, rct_window* window, rct_viewport* viewport) +{ + if (window->classification != WC_MAIN_WINDOW) + { + if (!underground) + { + int bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; + viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE; + if (!bit) return; + } + else + { + int bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; + viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; + if (bit) return; + } + window_invalidate(window); + } +} + /** - * + * * rct2: 0x006E7A3A */ void viewport_update_position(rct_window *window) { - //RCT2_CALLPROC_X(0x006E7A3A, 0, 0, 0, 0, (int)window, 0, 0); - - RCT2_CALLPROC_X(window->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)window, 0, 0); + window_event_resize_call(window); rct_viewport* viewport = window->viewport; if (!viewport)return; @@ -422,16 +450,15 @@ void viewport_update_position(rct_window *window) if (window->viewport_target_sprite != -1){ rct_sprite* sprite = &g_sprite_list[window->viewport_target_sprite]; - int height = map_element_height(0xFFFF & sprite->unknown.x, 0xFFFF & sprite->unknown.y) & 0xFFFF - 16; + int height = (map_element_height(0xFFFF & sprite->unknown.x, 0xFFFF & sprite->unknown.y) & 0xFFFF) - 16; int underground = sprite->unknown.z < height; - RCT2_CALLPROC_X(0x6E7A15, sprite->unknown.x, sprite->unknown.y, sprite->unknown.z, underground, (int)window, (int)viewport, 0); + viewport_set_underground_flag(underground, window, viewport); int center_x, center_y; center_2d_coordinates(sprite->unknown.x, sprite->unknown.y, sprite->unknown.z, ¢er_x, ¢er_y, window->viewport); - //sub_6E7DE1(center_x, center_y, window, viewport); - RCT2_CALLPROC_X(0x6E7DE1, center_x, center_y, 0, 0, (int)window, (int)viewport, 0); + sub_6E7DE1(center_x, center_y, window, viewport); return; } @@ -440,10 +467,9 @@ void viewport_update_position(rct_window *window) sint16 y = viewport->view_height / 2 + window->saved_view_y; sint16 z; - int curr_rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); - sub_689174(&x, &y, &z, curr_rotation); - - RCT2_CALLPROC_X(0x006E7A15, x, y, z, 0, (int)window, (int)viewport, 0); + sub_689174(&x, &y, &z); + + viewport_set_underground_flag(0, window, viewport); //Clamp to the map minimum value int at_map_edge = 0; @@ -457,12 +483,12 @@ void viewport_update_position(rct_window *window) } //Clamp to the map maximum value (scenario specific) - if (x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ - x = RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16); + if (x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, sint16)){ + x = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, sint16); at_map_edge = 1; } - if (y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16)){ - y = RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16); + if (y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, sint16)){ + y = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, sint16); at_map_edge = 1; } @@ -472,7 +498,7 @@ void viewport_update_position(rct_window *window) int z = map_element_height(x & 0xFFFF, y & 0xFFFF); int _2d_x, _2d_y; center_2d_coordinates(x, y, z, &_2d_x, &_2d_y, viewport); - + if (window->saved_view_x > 0){ _2d_x = min(_2d_x, window->saved_view_x); } @@ -506,8 +532,8 @@ void viewport_update_position(rct_window *window) y = -y; flags |= 2; } - x = (x + 7)/8; - y = (y + 7)/8; + x = (x + 7) / 8; + y = (y + 7) / 8; //If we are at the final zoom position if (!x && !y){ @@ -523,14 +549,11 @@ void viewport_update_position(rct_window *window) y += viewport->view_y; } - //sub_6E7DE1(x, y, window, viewport); - RCT2_CALLPROC_X(0x6E7DE1, x, y, 0, 0, (int)window, (int)viewport, 0); + sub_6E7DE1(x, y, window, viewport); } -void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, int top, int right, int bottom); - /** - * + * * rct2: 0x00685C02 * ax: left * bx: top @@ -543,8 +566,8 @@ void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, int left, i { if (right <= viewport->x) return; if (bottom <= viewport->y) return; - if (left >= viewport->x + viewport->width )return; - if (top >= viewport->y + viewport->height )return; + if (left >= viewport->x + viewport->width)return; + if (top >= viewport->y + viewport->height)return; int l = left, t = top, r = right, b = bottom; @@ -570,8 +593,8 @@ void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, int left, i top += 384; } //Paint - viewport_paint(viewport, dpi, left, top, right, bottom); - + viewport_paint(viewport, dpi, left, top, right, bottom); + #ifdef DEBUG_SHOW_DIRTY_BOX if (viewport != g_viewport_list){ gfx_fill_rect_inset(dpi, l, t, r-1, b-1, 0x2, 0x30); @@ -581,7 +604,7 @@ void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, int left, i } /** -* +* * rct2: 0x0068615B * ebp: ebp */ @@ -636,8 +659,6 @@ void paint_attached_ps(paint_struct* ps, paint_struct* attached_ps, rct_drawpixe } void sub_688485(){ - //RCT2_CALLPROC_EBPSAFE(0x688485); - //return; rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); paint_struct* ps = RCT2_GLOBAL(0xEE7884, paint_struct*); paint_struct* previous_ps = ps->var_24; @@ -684,7 +705,7 @@ void sub_688485(){ if (!(ps->var_1A & 1)) gfx_draw_sprite(dpi, image_id, x, y, ps->var_04); else - RCT2_CALLPROC_X(0x00681DE2, 0, image_id, x, y, 0, (int)dpi, ps->var_04); + RCT2_CALLPROC_X(0x00681DE2, 0, image_id, x, y, 0, (int)dpi, ps->var_04); if (ps->var_20 != 0){ ps = ps->var_20; @@ -698,20 +719,55 @@ void sub_688485(){ } -int sub_0x686806(rct_sprite* sprite, int eax, int ecx, int edx){ +int sub_0x686806(rct_sprite* sprite, int eax, int image_id, int ecx, int edx){ int ebp = (eax >> 8) & 0xFF; edx <<= 16; ebp += RCT2_GLOBAL(0x9DEA56, uint16); RCT2_GLOBAL(0xF1AD28, uint32) = 0; RCT2_GLOBAL(0xF1AD2C, uint32) = 0; edx = (edx >> 16) | (ebp << 16); - ebp = RCT2_GLOBAL(0xEE7888, uint32); - if ((uint32)ebp >= RCT2_GLOBAL(0xEE7880, uint32)) return 1; - //686840 not finished + + //Not a paint struct but something similar + paint_struct* ps = RCT2_GLOBAL(0xEE7888, paint_struct*); + + if ((uint32)ps >= RCT2_GLOBAL(0xEE7880, uint32)) return 1; + + ps->image_id = image_id; + + rct_g1_element *g1Element = &g1Elements[image_id & 0x7FFFF]; + + eax = (eax & 0xFF) + RCT2_GLOBAL(0x9DE568, uint16); + ecx = (ecx & 0xFF) + RCT2_GLOBAL(0x9DE56C, uint16); + + int x = ecx - eax; + int y = (ecx + eax) / 2 - (edx & 0xFFFF); + + ps->x = x; + ps->y = y; + + int left = x + g1Element->x_offset; + int bottom = y + g1Element->y_offset; + + int right = left + g1Element->width; + int top = bottom + g1Element->height; + + RCT2_GLOBAL(0xF1AD1C, uint16) = left; + RCT2_GLOBAL(0xF1AD1E, uint16) = bottom; + + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + + if (right <= dpi->x)return 1; + if (top <= dpi->y)return 1; + if (left > dpi->x + dpi->width) return 1; + if (bottom > dpi->y + dpi->height) return 1; + + RCT2_GLOBAL(0x9DE568, uint16); + //686918 not finished return 0; } + /** * Litter Paint Setup?? * rct2: 0x006736FC @@ -735,7 +791,7 @@ void sub_0x6736FC(rct_litter* litter, int ebx, int edx){ RCT2_GLOBAL(0x9DEA54, uint16) = 0xFFFC; RCT2_GLOBAL(0x9DEA56, uint16) = edx + 2; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION,uint32)){ + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ case 0: //0x686806 break; @@ -756,28 +812,28 @@ void sub_0x6736FC(rct_litter* litter, int ebx, int edx){ * Paint Quadrant * rct2: 0x0069E8B0 */ -void sub_0x69E8B0(uint32 eax, uint32 ecx){ +void sub_0x69E8B0(uint16 eax, uint16 ecx){ uint32 _eax = eax, _ecx = ecx; rct_drawpixelinfo* dpi; - if (RCT2_GLOBAL(0x9DEA6F,uint8) & 1) return; - - dpi = RCT2_GLOBAL(0x140E9A8,rct_drawpixelinfo*); - + if (RCT2_GLOBAL(0x9DEA6F, uint8) & 1) return; + + dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000)return; - + if (dpi->zoom_level > 2) return; - + if (eax > 0x2000)return; if (ecx > 0x2000)return; - + //push eax, ecx - eax = (eax&0x1FE0)<<3 | (ecx>>5); + eax = (eax & 0x1FE0) << 3 | (ecx >> 5); int sprite_idx = RCT2_ADDRESS(0xF1EF60, uint16)[eax]; if (sprite_idx == SPRITE_INDEX_NULL) return; - - for (rct_sprite* spr = &g_sprite_list[sprite_idx]; sprite_idx != SPRITE_INDEX_NULL; sprite_idx = spr->unknown.var_02){ + + for (rct_sprite* spr = &g_sprite_list[sprite_idx]; sprite_idx != SPRITE_INDEX_NULL; sprite_idx = spr->unknown.next_in_quadrant){ spr = &g_sprite_list[sprite_idx]; dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); @@ -805,19 +861,358 @@ void sub_0x69E8B0(uint32 eax, uint32 ecx){ case SPRITE_IDENTIFIER_PEEP: RCT2_CALLPROC_X(0x68F0FB, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); break; - case SPRITE_IDENTIFIER_FLOATING_TEXT: + case SPRITE_IDENTIFIER_MISC: RCT2_CALLPROC_X(0x672AC9, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); break; case SPRITE_IDENTIFIER_LITTER: RCT2_CALLPROC_X(0x6736FC, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); break; - //I am pretty sure there are no other sprite identifier types } - //RCT2_CALLPROC_X(RCT2_ADDRESS(0x98BC40,uint32)[spr->unknown.sprite_identifier], eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); } +} - //RCT2_CALLPROC_X(0x69E8B0, _eax, 0, _ecx, 0, 0, 0, 0); - //return; +/*rct2: 0x006C42D9*/ +int sub_6C42D9(rct_string_id string_id, int scroll, int ebp) +{ + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + if (dpi->zoom_level != 0) return 0x626; + RCT2_GLOBAL(0x9D7A80, uint32_t)++; + uint32_t edx = 0xFFFFFFFF; + for (int i = 0; i < 0x20; i++) + { + uint8_t* unknown_pointer = RCT2_ADDRESS(0x9C3840, uint8_t) + 0xA12 * i; + if (edx >= *((uint32_t*)(unknown_pointer + 0x0E))) + { + edx = *((uint32_t*)(unknown_pointer + 0x0E)); + RCT2_GLOBAL(0x9D7A84, uint32_t) = i; + RCT2_GLOBAL(0x9D7A88, uint32_t) = (uint32_t)unknown_pointer; + } + if (*((rct_string_id*)unknown_pointer) == string_id && + *((uint32_t*)(unknown_pointer + 0x02)) == RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32_t) && + *((uint32_t*)(unknown_pointer + 0x06)) == RCT2_GLOBAL(0x13CE956, uint32_t) && + *((uint16_t*)(unknown_pointer + 0x0A)) == scroll && + *((uint16_t*)(unknown_pointer + 0x0C)) == ebp) + { + *((uint32_t*)(unknown_pointer + 0x0E)) = RCT2_GLOBAL(0x9D7A80, uint32_t); + return i + 0x606; + } + } + uint8_t* unknown_pointer = RCT2_GLOBAL(0x9D7A88, uint8_t*); + *((rct_string_id*)unknown_pointer) = string_id; + *((uint32_t*)(unknown_pointer + 0x02)) = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32_t); + *((uint32_t*)(unknown_pointer + 0x06)) = RCT2_GLOBAL(0x13CE956, uint32_t); + *((uint16_t*)(unknown_pointer + 0x0A)) = scroll; + *((uint16_t*)(unknown_pointer + 0x0C)) = ebp; + *((uint32_t*)(unknown_pointer + 0x0E)) = RCT2_GLOBAL(0x9D7A80, uint32_t); + unknown_pointer += 0x12; + memset(unknown_pointer, 0, 0x280 * 4); + format_string(RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char), string_id, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + int al = RCT2_GLOBAL(0x13CE959, uint8_t); + int edi = al & 0x7F; + int offs = 0; + if (al >= 0x80) offs = 2; + RCT2_GLOBAL(0x9D7A8C, uint8_t) = RCT2_ADDRESS(0x0141FC47, uint8_t)[offs + edi * 8]; + int16_t* unk = RCT2_ADDRESS(0x992FB8, uint16_t*)[ebp]; + uint8_t* format_result = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8_t); + while (true) + { + al = *format_result; + format_result++; + if (al == 0) + { + format_result = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + continue; + } + if (al <= FORMAT_COLOUR_CODE_END && al >= FORMAT_COLOUR_CODE_START) + { + al -= FORMAT_COLOUR_CODE_START; + RCT2_GLOBAL(0x9D7A8C, uint8_t) = RCT2_ADDRESS(RCT2_GLOBAL(0x9FF048, uint32_t), uint8_t)[al * 4]; + continue; + } + if (al < 0x20) continue; + al -= 0x20; + int edx = RCT2_ADDRESS(0x141EBA8, uint8_t)[al]; + uint8_t* unk2 = &(RCT2_ADDRESS(0xF4393C, uint8)[al * 8]); + while (true) + { + if (scroll != 0) + { + scroll--; + unk2++; + edx--; + if (edx == 0) break; + } + else + { + int16_t eax = *unk; + if (eax == -1) return RCT2_GLOBAL(0x9D7A84, uint32_t) + 0x606; + if (eax > -1) + { + uint8_t* dst = &unknown_pointer[eax]; + int ah = *unk2; + int al = RCT2_GLOBAL(0x9D7A8C, uint8_t); + while (true) + { + if (ah & 1) *dst = al; + ah >>= 1; + dst += 0x40; + if (ah == 0) break; + } + } + unk2++; + unk++; + edx--; + if (edx == 0) break; + } + } + } +} + +/* rct2: 0x006B9CC4 */ +void viewport_banner_paint_setup(uint32_t direction, int edx, rct_map_element* map_element) +{ + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + RCT2_GLOBAL(0x9DE570, uint8_t) = 0xC; + if (dpi->zoom_level > 1 || RCT2_GLOBAL(0x9DEA6F, uint8_t) & 1) return; + edx -= 16; + rct_scenery_entry* banner_scenery = g_bannerSceneryEntries[gBanners[map_element->properties.banner.index].type]; + direction += map_element->properties.banner.position; + direction &= 3; + RCT2_GLOBAL(0x9DEA56, uint16_t) = edx + 2; + RCT2_GLOBAL(0x9DEA52, uint32_t) = RCT2_ADDRESS(0x98D884, uint32_t)[direction * 2]; + int ebx = (direction << 1) + banner_scenery->image; + ebx += (gBanners[map_element->properties.banner.index].colour << 19) | 0x20000000; + if (map_element->flags & 0x10)//if being placed (ghost appearance) + { + RCT2_GLOBAL(0x9DE570, uint8_t) = 0; + ebx &= 0x7FFFF; + ebx |= RCT2_ADDRESS(0x993CC4, uint32_t)[RCT2_GLOBAL(0x9AACBF, uint8_t)]; + } + RCT2_CALLPROC_X(RCT2_ADDRESS(0x98197C, uint32_t)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)], + 0x1500, ebx, 0, edx, 1, 1, RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)); + RCT2_GLOBAL(0x9DEA52, uint32_t) = RCT2_ADDRESS(0x98D888, uint32_t)[direction * 2]; + ebx++; + RCT2_CALLPROC_X(RCT2_ADDRESS(0x98197C, uint32_t)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)], + 0x1500, ebx, 0, edx, 1, 1, RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)); + direction ^= 2; + direction--; + if (direction >= 2 || (map_element->flags & 0x10)) return; + int ebp = banner_scenery->banner.var_06; + ebp += direction; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32_t) = 0; + RCT2_GLOBAL(0x13CE956, uint32_t) = 0; + rct_string_id string_id = 0xBA5;//no entry + if (!(gBanners[map_element->properties.banner.index].flags & BANNER_FLAG_NO_ENTRY)) + { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16_t) = gBanners[map_element->properties.banner.index].string_idx; + string_id = 0x6C3; + } + format_string(RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char), string_id, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16_t) = 0x1C0; + uint16_t string_width = gfx_get_string_width(RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char)); + uint16_t scroll = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32_t) >> 1) % string_width; + RCT2_CALLPROC_X(RCT2_ADDRESS(0x98199C, uint32_t)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)], + 0x1500, sub_6C42D9(string_id, scroll, ebp), 0, edx + 22, 1, 1, 0); +} + +/*rct2: 0x0068B35F*/ +void sub_68B35F(int ax, int cx) +{ + if (ax < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16_t) && + cx < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16_t) && + ax >= 32 && cx >= 32) + { + RCT2_GLOBAL(0x141E9B4, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9D8, uint32_t) = 0xFFFF; + RCT2_GLOBAL(0x141E9DC, uint32_t) = 0xFFFF; + //loc_68B3FB: Another function jumps to here. We need to split this! + RCT2_GLOBAL(0x141F56A, uint16_t) = 0; + RCT2_GLOBAL(0x9E3138, uint8_t) = 0xFF; + RCT2_GLOBAL(0x9E30B6, uint8_t) = 0xFF; + RCT2_GLOBAL(0x9E323C, uint8_t) = 0xFF; + RCT2_GLOBAL(0x9DE56A, uint16_t) = ax; + RCT2_GLOBAL(0x9DE56E, uint16_t) = cx; + RCT2_GLOBAL(0x9DE574, uint16_t) = ax; + RCT2_GLOBAL(0x9DE576, uint16_t) = cx; + int dx = cx; + int esi = dx; + esi <<= 8; + esi |= ax; + esi >>= 3; + int ax_tmp = ax; + int cx_tmp = cx; + rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(esi / 4); + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)) + { + case 0: + dx = ax + cx; + break; + case 1: + ax += 32; + dx = cx - ax; + break; + case 2: + ax += 32; + cx += 32; + dx = -(ax + cx); + break; + case 3: + cx += 32; + dx = ax - cx; + break; + } + dx /= 2; + // Display little yellow arrow when building footpaths? + if ((RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16_t) & 4) && + RCT2_GLOBAL(0x9DE56A, uint16_t) == RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_X, uint16_t) && + RCT2_GLOBAL(0x9DE56E, uint16_t) == RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Y, uint16_t)) + { + + int ebx = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t); + RCT2_GLOBAL(0x9DE568, uint16_t) = ax; + RCT2_GLOBAL(0x9DE56C, uint16_t) = cx; + int dl = RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8_t) & 3; + ebx += dl; + ebx &= 3; + dl = RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8_t) & 0xFC; + ebx += dl; + ebx += 0x20900C27; + int d = RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Z, uint16_t); + RCT2_GLOBAL(0x9DE570, uint8_t) = 0; + RCT2_GLOBAL(0x9DEA52, uint16_t) = 0; + RCT2_GLOBAL(0x9DEA54, uint16_t) = 0; + RCT2_GLOBAL(0x9DEA56, uint16_t) = d + 18; + RCT2_CALLPROC_X( + (int)RCT2_ADDRESS(0x0098197C, uint32_t*)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)], + 0xFF00, ebx, cx & 0xFF00, d, 32, 32, RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)); + } + int bx = dx + 52; + if (bx > dpi->y) + { + rct_map_element* element = map_element;//push map_element + bx = element->clearance_height; + if (!map_element_is_last_for_tile(element)) + { + while (true) + { + element++; + bx = max(bx, element->clearance_height); + if (map_element_is_last_for_tile(element)) break; + } + } + if (map_element_get_type(element) == MAP_ELEMENT_TYPE_SURFACE && + (element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) != 0) + { + bx = (element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) << 1; + } + bx <<= 3; + dx -= bx; + dx -= 32; + element = map_element;//pop map_element + dx -= dpi->height; + if (dx < dpi->y) + { + RCT2_GLOBAL(0x9DE568, uint16_t) = ax; + RCT2_GLOBAL(0x9DE56C, uint16_t) = cx; + RCT2_GLOBAL(0x9DE57C, uint16_t) = 0; + while (true) + { + int direction = (map_element->type + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)) & MAP_ELEMENT_DIRECTION_MASK; + dx = map_element->base_height * 8; + uint32_t dword_9DE574 = RCT2_GLOBAL(0x9DE574, uint32_t); + RCT2_GLOBAL(0x9DE578, rct_map_element*) = map_element; + //setup the painting of for example: the underground, signs, rides, scenery, etc. + switch (map_element_get_type(map_element)) + { + case MAP_ELEMENT_TYPE_SURFACE: + RCT2_CALLPROC_X(0x66062C, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_PATH: + RCT2_CALLPROC_X(0x6A3590, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_TRACK: + RCT2_CALLPROC_X(0x6C4794, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_SCENERY: + RCT2_CALLPROC_X(0x6DFF47, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + RCT2_CALLPROC_X(0x664FD4, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_FENCE: + RCT2_CALLPROC_X(0x6E44B0, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + RCT2_CALLPROC_X(0x6B7F0C, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_BANNER: + //there are still some small localisation glitches, + //because the old function still gets called sometimes + //viewport_banner_paint_setup(direction, dx, map_element); + //Until that is solved, use the original function instead + RCT2_CALLPROC_X(0x6B9CC4, 0, 0, direction, dx, (int)map_element, 0, 0); + break; + default: + // This is a little hack for taking care of undefined map_elements + // 8cars MOM used a dirty version of this to skip drawing certain elements + if (map_element_is_last_for_tile(map_element)) + return; + map_element++; + break; + } + RCT2_GLOBAL(0x9DE574, uint32_t) = dword_9DE574; + int stop = map_element_is_last_for_tile(map_element); + map_element++; + if (stop) break; + } + } + } + } + else + { + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + int dx; + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)) + { + case 0: + dx = ax + cx; + break; + case 1: + ax += 32; + dx = cx - ax; + break; + case 2: + ax += 32; + cx += 32; + dx = -(ax + cx); + break; + case 3: + cx += 32; + dx = ax - cx; + break; + } + dx /= 2; + dx -= 16; + int bx = dx + 32; + if (bx <= dpi->y) return; + dx -= 20; + dx -= dpi->height; + if (dx >= dpi->y) return; + RCT2_GLOBAL(0x9DE568, uint16_t) = ax; + RCT2_GLOBAL(0x9DE56C, uint16_t) = cx; + RCT2_GLOBAL(0x9DE570, uint8_t) = 0; + RCT2_CALLPROC_X((int)RCT2_ADDRESS(0x98196C, uint32_t*)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)], + 0xFF00, 3123, cx & 0xFF00, 16, 32, 32, RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)); + } } /** @@ -827,36 +1222,42 @@ void sub_0x69E8B0(uint32 eax, uint32 ecx){ void sub_0x68B6C2(){ rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); sint16 ax, bx, cx, dx; + uint16 num_vertical_quadrants = 0; + rct_xy16 mapTile; switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ case 0: - ax = dpi->y; - bx = dpi->x; + mapTile.x = dpi->x & 0xFFE0; + mapTile.y = (dpi->y - 16) & 0xFFE0; + + bx = mapTile.x / 2; + mapTile.x = mapTile.y - bx; + mapTile.y = mapTile.y + bx; - ax -= 16; - bx &= 0xFFE0; - ax &= 0xFFE0; - bx >>= 1; - cx = ax; - ax -= bx; - cx += bx; - ax &= 0xFFE0; - cx &= 0xFFE0; - dx = dpi->height; - dx += 2128; - dx >>= 5; - for (int i = dx; i > 0; --i){ - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); - sub_0x69E8B0(ax, cx); - cx += 0x20; - ax -= 0x20; - sub_0x69E8B0(ax, cx); - ax += 0x20; - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); - sub_0x69E8B0(ax, cx); - ax += 0x20; - cx -= 0x20; - sub_0x69E8B0(ax, cx); - cx += 0x20; + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + num_vertical_quadrants = (dpi->height + 2128) / 32; + + for (; num_vertical_quadrants > 0; --num_vertical_quadrants){ + sub_68B35F(mapTile.x, mapTile.y); + sub_0x69E8B0(mapTile.x, mapTile.y); + + mapTile.x -= 32; + mapTile.y += 32; + + sub_0x69E8B0(mapTile.x, mapTile.y); + + mapTile.x += 32; + + sub_68B35F(mapTile.x, mapTile.y); + sub_0x69E8B0(mapTile.x, mapTile.y); + + mapTile.x += 32; + mapTile.y -= 32; + + sub_0x69E8B0(mapTile.x, mapTile.y); + + mapTile.y += 32; } break; case 1: @@ -866,7 +1267,7 @@ void sub_0x68B6C2(){ bx &= 0xFFE0; ax &= 0xFFE0; bx >>= 1; - cx = ax; + cx = ax; ax = -ax; ax -= bx; cx -= bx; @@ -877,13 +1278,13 @@ void sub_0x68B6C2(){ dx += 0x860; dx >>= 5; for (int i = dx; i > 0; i--){ - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); + sub_68B35F(ax, cx); sub_0x69E8B0(ax, cx); ax -= 0x20; cx -= 0x20; sub_0x69E8B0(ax, cx); cx += 0x20; - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); + sub_68B35F(ax, cx); sub_0x69E8B0(ax, cx); ax += 0x20; cx += 0x20; @@ -908,13 +1309,13 @@ void sub_0x68B6C2(){ dx += 0x860; dx >>= 5; for (int i = dx; i > 0; i--){ - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); + sub_68B35F(ax, cx); sub_0x69E8B0(ax, cx); ax += 0x20; cx -= 0x20; sub_0x69E8B0(ax, cx); ax -= 0x20; - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); + sub_68B35F(ax, cx); sub_0x69E8B0(ax, cx); ax -= 0x20; cx += 0x20; @@ -940,13 +1341,13 @@ void sub_0x68B6C2(){ dx += 0x860; dx >>= 5; for (int i = dx; i > 0; i--){ - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); + sub_68B35F(ax, cx); sub_0x69E8B0(ax, cx); ax += 0x20; cx += 0x20; sub_0x69E8B0(ax, cx); cx -= 0x20; - RCT2_CALLPROC_X(0x68B35F, ax, 0, cx, 0, 0, 0, 0); + sub_68B35F(ax, cx); sub_0x69E8B0(ax, cx); ax -= 0x20; cx -= 0x20; @@ -957,6 +1358,133 @@ void sub_0x68B6C2(){ } } +void sub_688217_helper(uint16 ax, uint8 flag) +{ + paint_struct *ps; + paint_struct *ps_next = RCT2_GLOBAL(0x00EE7884, paint_struct*); + + do { + ps = ps_next; + ps_next = ps_next->var_24; + if (ps_next == NULL) return; + } while (ax > ps_next->var_18); + + RCT2_GLOBAL(0x00F1AD14, paint_struct*) = ps; + + do { + ps = ps->var_24; + if (ps == NULL) break; + + if (ps->var_18 > ax + 1) { + ps->var_1B = 1 << 7; + } else if (ps->var_18 == ax + 1) { + ps->var_1B = (1 << 1) | (1 << 0); + } else if (ps->var_18 == ax) { + ps->var_1B = flag | (1 << 0); + } + } while (ps->var_18 <= ax + 1); + + ps = RCT2_GLOBAL(0x00F1AD14, paint_struct*); + + while (true) { + while (true) { + ps_next = ps->var_24; + if (ps_next == NULL) return; + if (ps_next->var_1B & (1 << 7)) return; + if (ps_next->var_1B & (1 << 0)) break; + ps = ps_next; + } + + ps_next->var_1B &= ~(1 << 0); + RCT2_GLOBAL(0x00F1AD18, paint_struct*) = ps; + + uint16 my_attached_x = ps_next->attached_x; + uint16 my_attached_y = ps_next->attached_y; + uint16 my_some_x = ps_next->some_x; + uint16 my_some_y = ps_next->some_y; + uint16 my_other_x = ps_next->other_x; + uint16 my_other_y = ps_next->other_y; + + while (true) { + ps = ps_next; + ps_next = ps_next->var_24; + if (ps_next == NULL) break; + if (ps_next->var_1B & (1 << 7)) break; + if (!(ps_next->var_1B & (1 << 1))) continue; + + int yes = 0; + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { + case 0: + if (my_some_y >= ps_next->some_x && my_other_y >= ps_next->attached_y && my_other_x >= ps_next->attached_x + && !(my_some_x < ps_next->some_y && my_attached_y < ps_next->other_y && my_attached_x < ps_next->other_x)) + yes = 1; + break; + case 1: + if (my_some_y >= ps_next->some_x && my_other_y >= ps_next->attached_y && my_other_x < ps_next->attached_x + && !(my_some_x < ps_next->some_y && my_attached_y < ps_next->other_y && my_attached_x >= ps_next->other_x)) + yes = 1; + break; + case 2: + if (my_some_y >= ps_next->some_x && my_other_y < ps_next->attached_y && my_other_x < ps_next->attached_x + && !(my_some_x < ps_next->some_y && my_attached_y >= ps_next->other_y && my_attached_x >= ps_next->other_x)) + yes = 1; + break; + case 3: + if (my_some_y >= ps_next->some_x && my_other_y < ps_next->attached_y && my_other_x >= ps_next->attached_x + && !(my_some_x < ps_next->some_y && my_attached_y >= ps_next->other_y && my_attached_x < ps_next->other_x)) + yes = 1; + break; + } + + if (yes) { + ps->var_24 = ps_next->var_24; + paint_struct *ps_temp = RCT2_GLOBAL(0x00F1AD18, paint_struct*)->var_24; + RCT2_GLOBAL(0x00F1AD18, paint_struct*)->var_24 = ps_next; + ps_next->var_24 = ps_temp; + ps_next = ps; + } + } + + ps = RCT2_GLOBAL(0x00F1AD18, paint_struct*); + } +} + +/** +* +* rct2: 0x00688217 +*/ +void sub_688217() +{ + paint_struct *ps = RCT2_GLOBAL(0x00EE7888, paint_struct*); + paint_struct *ps_next; + RCT2_GLOBAL(0x00EE7888, uint32) += 0x34; // 0x34 is size of paint_struct? + RCT2_GLOBAL(0x00EE7884, paint_struct*) = ps; + ps->var_24 = NULL; + uint32 edi = RCT2_GLOBAL(0x00F1AD0C, uint32); + if (edi == -1) + return; + + do { + ps_next = RCT2_GLOBAL(0x00F1A50C + 4 * edi, paint_struct*); + if (ps_next != NULL) { + ps->var_24 = ps_next; + do { + ps = ps_next; + ps_next = ps_next->var_24; + } while (ps_next != NULL); + } + } while (++edi <= RCT2_GLOBAL(0x00F1AD10, uint32)); + + uint32 eax = RCT2_GLOBAL(0x00F1AD0C, uint32); + + sub_688217_helper(eax & 0xFFFF, 1 << 1); + + eax = RCT2_GLOBAL(0x00F1AD0C, uint32); + + while (++eax < RCT2_GLOBAL(0x00F1AD10, uint32)) + sub_688217_helper(eax & 0xFFFF, 0); +} + /** * * rct2:0x00685CBF @@ -968,8 +1496,6 @@ void sub_0x68B6C2(){ * ebp: bottom */ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, int top, int right, int bottom){ - //RCT2_CALLPROC_X(0x00685CBF, left, top, 0, right, (int)viewport, (int)dpi, bottom); - //return; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) = viewport->flags; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16) = viewport->zoom; @@ -982,8 +1508,8 @@ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, in left &= bitmask; top &= bitmask; - RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16) = left; - RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, uint16) = top; + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, sint16) = left; + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, sint16) = top; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_WIDTH, uint16) = width; RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_HEIGHT, uint16) = height; @@ -991,11 +1517,11 @@ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, in RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_PITCH, uint16) = (dpi->width + dpi->pitch) - width; - int x = (sint16)(left - (sint16)(viewport->view_x & bitmask)); + sint16 x = (sint16)(left - (sint16)(viewport->view_x & bitmask)); x >>= viewport->zoom; x += viewport->x; - int y = (sint16)(top - (sint16)(viewport->view_y & bitmask)); + sint16 y = (sint16)(top - (sint16)(viewport->view_y & bitmask)); y >>= viewport->zoom; y += viewport->y; @@ -1003,16 +1529,16 @@ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, in RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_BITS_PTR, uint8*) = bits_pointer; rct_drawpixelinfo* dpi2 = RCT2_ADDRESS(RCT2_ADDRESS_VIEWPORT_DPI, rct_drawpixelinfo); - dpi2->y = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, uint16); + dpi2->y = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, sint16); dpi2->height = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_HEIGHT, uint16); dpi2->zoom_level = (uint8)RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16); //Splits the screen into 32 pixel columns and renders them. - for (x = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16) & 0xFFFFFFE0; - x < RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16) + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_WIDTH, uint16); + for (x = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, sint16) & 0xFFFFFFE0; + x < RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_WIDTH, uint16); x += 32){ - int start_x = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, uint16); + int start_x = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, sint16); int width_col = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_WIDTH, uint16); bits_pointer = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_BITS_PTR, uint8*); int pitch = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_PITCH, uint16); @@ -1049,38 +1575,133 @@ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, in int ebp = 0, ebx = 0, esi = 0, ecx = 0; sub_0x68615B(0xEE788C); //Memory copy sub_0x68B6C2(); - //RCT2_CALLPROC_X(0x68B6C2, 0, 0, 0, 0, 0, 0, 0); //Big function call 4 rotation versions - RCT2_CALLPROC_X(0x688217, start_x, ebx, ecx, (int)bits_pointer, esi, (int)dpi2, ebp); //Move memory + sub_688217(); sub_688485(); - //RCT2_CALLPROC_EBPSAFE(0x688485); //Big function call int weather_colour = RCT2_ADDRESS(0x98195C, uint32)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_GLOOM, uint8)]; - if ((weather_colour != -1) && (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000) && (RCT2_GLOBAL(0x9DEA6F, uint8) & 1)){ - dpi2 = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + if ((weather_colour != -1) && (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000)) && (!(RCT2_GLOBAL(0x9DEA6F, uint8) & 1))){ gfx_fill_rect(dpi2, dpi2->x, dpi2->y, dpi2->width + dpi2->x - 1, dpi2->height + dpi2->y - 1, weather_colour); } RCT2_CALLPROC_EBPSAFE(0x6860C3); //string related - } - - //RCT2_CALLPROC_X(0x00685CBF, left, top, 0, right, (int)viewport, (int)dpi, bottom); + } } /** - * + * + * rct2: 0x00688972 + * In: + * screen_x: eax + * screen_y: ebx + * Out: + * x: ax + * y: bx + * map_element: edx ? + * viewport: edi + */ +void sub_688972(int screenX, int screenY, sint16 *x, sint16 *y, rct_viewport **viewport) { + sint16 my_x, my_y; + int z, interactionType; + rct_viewport *myViewport; + get_map_coordinates_from_pos(screenX, screenY, VIEWPORT_INTERACTION_MASK_TERRAIN, &my_x, &my_y, &interactionType, NULL, &myViewport); + if (interactionType == VIEWPORT_INTERACTION_ITEM_NONE) { + *x = 0x8000; + return; + } + + RCT2_GLOBAL(0x00F1AD34, sint16) = my_x; + RCT2_GLOBAL(0x00F1AD36, sint16) = my_y; + RCT2_GLOBAL(0x00F1AD38, sint16) = my_x + 31; + RCT2_GLOBAL(0x00F1AD3A, sint16) = my_y + 31; + + rct_xy16 start_vp_pos = screen_coord_to_viewport_coord(myViewport, screenX, screenY); + rct_xy16 map_pos = { my_x + 16, my_y + 16 }; + + for (int i = 0; i < 5; i++) { + z = map_element_height(map_pos.x, map_pos.y); + map_pos = viewport_coord_to_map_coord(start_vp_pos.x, start_vp_pos.y, z); + map_pos.x = clamp(RCT2_GLOBAL(0x00F1AD34, sint16), map_pos.x, RCT2_GLOBAL(0x00F1AD38, sint16)); + map_pos.y = clamp(RCT2_GLOBAL(0x00F1AD36, sint16), map_pos.y, RCT2_GLOBAL(0x00F1AD3A, sint16)); + } + + *x = map_pos.x; + *y = map_pos.y; + + if (viewport != NULL) *viewport = myViewport; +} + +/** + * * rct2: 0x0068958D */ -void screen_pos_to_map_pos(short *x, short *y) +void screen_pos_to_map_pos(sint16 *x, sint16 *y, int *direction) { - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = *x; - ebx = *y; - RCT2_CALLFUNC_X(0x0068958D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *x = eax & 0xFFFF; - *y = ebx & 0xFFFF; + sub_688972(*x, *y, x, y, NULL); + if (*x == (sint16)0x8000) + return; + + int my_direction; + int dist_from_center_x = abs(*x % 32); + int dist_from_center_y = abs(*y % 32); + if (dist_from_center_x > 8 && dist_from_center_x < 24 && + dist_from_center_y > 8 && dist_from_center_y < 24) { + my_direction = 4; + } else { + sint16 mod_x = *x & 0x1F; + sint16 mod_y = *y & 0x1F; + if (mod_x <= 16) { + if (mod_y < 16) { + my_direction = 2; + } else { + my_direction = 3; + } + } else { + if (mod_y < 16) { + my_direction = 1; + } else { + my_direction = 0; + } + } + } + + *x = *x & ~0x1F; + *y = *y & ~0x1F; + if (direction != NULL) *direction = my_direction; +} + +rct_xy16 screen_coord_to_viewport_coord(rct_viewport *viewport, uint16 x, uint16 y) +{ + rct_xy16 ret; + ret.x = ((x - viewport->x) << viewport->zoom) + viewport->view_x; + ret.y = ((y - viewport->y) << viewport->zoom) + viewport->view_y; + return ret; +} + +rct_xy16 viewport_coord_to_map_coord(int x, int y, int z) +{ + rct_xy16 ret; + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { + case 0: + ret.x = -x / 2 + y + z; + ret.y = x / 2 + y + z; + break; + case 1: + ret.x = -x / 2 - y - z; + ret.y = -x / 2 + y + z; + break; + case 2: + ret.x = x / 2 - y - z; + ret.y = -x / 2 - y - z; + break; + case 3: + ret.x = x / 2 + y + z; + ret.y = x / 2 - y - z; + break; + } + return ret; } /** - * + * * rct2: 0x00664689 */ void show_gridlines() @@ -1099,7 +1720,7 @@ void show_gridlines() } /** - * + * * rct2: 0x006646B4 */ void hide_gridlines() @@ -1109,7 +1730,7 @@ void hide_gridlines() RCT2_GLOBAL(0x009E32B0, uint8)--; if (RCT2_GLOBAL(0x009E32B0, uint8) == 0) { if ((mainWindow = window_get_main()) != NULL) { - if (!gGeneral_config.always_show_gridlines) { + if (!gConfigGeneral.always_show_gridlines) { mainWindow->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; window_invalidate(mainWindow); } @@ -1118,14 +1739,14 @@ void hide_gridlines() } /** - * + * * rct2: 0x00664E8E */ void show_land_rights() { rct_window *mainWindow; - if (RCT2_GLOBAL(0x009E32B2, uint8) != 0) { + if (RCT2_GLOBAL(0x009E32B2, uint8) == 0) { if ((mainWindow = window_get_main()) != NULL) { if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP)) { mainWindow->viewport->flags |= VIEWPORT_FLAG_LAND_OWNERSHIP; @@ -1137,8 +1758,8 @@ void show_land_rights() } /** - * - * rct2: 0x00664E8E + * + * rct2: 0x00664EB9 */ void hide_land_rights() { @@ -1156,14 +1777,14 @@ void hide_land_rights() } /** - * + * * rct2: 0x00664EDD */ void show_construction_rights() { rct_window *mainWindow; - if (RCT2_GLOBAL(0x009E32B3, uint8) != 0) { + if (RCT2_GLOBAL(0x009E32B3, uint8) == 0) { if ((mainWindow = window_get_main()) != NULL) { if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS)) { mainWindow->viewport->flags |= VIEWPORT_FLAG_CONSTRUCTION_RIGHTS; @@ -1175,7 +1796,7 @@ void show_construction_rights() } /** - * + * * rct2: 0x00664F08 */ void hide_construction_rights() @@ -1194,52 +1815,125 @@ void hide_construction_rights() } /** - * + * * rct2: 0x006CB70A */ void viewport_set_visibility(uint8 mode) { - rct_window* window = window_get_main(); + rct_window* window = window_get_main(); - if(window != NULL) { - rct_viewport* edi = window->viewport; - uint32 invalidate = 0; + if (window != NULL) { + rct_viewport* edi = window->viewport; + uint32 invalidate = 0; - switch(mode) { - case 0: { //Set all these flags to 0, and invalidate if any were active - uint16 mask = VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_SEETHROUGH_RIDES | - VIEWPORT_FLAG_SEETHROUGH_SCENERY | VIEWPORT_FLAG_INVISIBLE_SUPPORTS | - VIEWPORT_FLAG_LAND_HEIGHTS | VIEWPORT_FLAG_TRACK_HEIGHTS | - VIEWPORT_FLAG_PATH_HEIGHTS | VIEWPORT_FLAG_INVISIBLE_PEEPS | - VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL; + switch (mode) { + case 0: { //Set all these flags to 0, and invalidate if any were active + uint16 mask = VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_SEETHROUGH_RIDES | + VIEWPORT_FLAG_SEETHROUGH_SCENERY | VIEWPORT_FLAG_INVISIBLE_SUPPORTS | + VIEWPORT_FLAG_LAND_HEIGHTS | VIEWPORT_FLAG_TRACK_HEIGHTS | + VIEWPORT_FLAG_PATH_HEIGHTS | VIEWPORT_FLAG_INVISIBLE_PEEPS | + VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL; - invalidate += edi->flags & mask; - edi->flags &= ~mask; - break; - } - case 1: //6CB79D - case 4: //6CB7C4 - //Set underground on, invalidate if it was off - invalidate += !(edi->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE); - edi->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; - break; - case 2: //6CB7EB - //Set track heights on, invalidate if off - invalidate += !(edi->flags & VIEWPORT_FLAG_TRACK_HEIGHTS); - edi->flags |= VIEWPORT_FLAG_TRACK_HEIGHTS; - break; - case 3: //6CB7B1 - case 5: //6CB7D8 - //Set underground off, invalidate if it was on - invalidate += edi->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; - edi->flags &= ~((uint16)VIEWPORT_FLAG_UNDERGROUND_INSIDE); - break; - } - if (invalidate != 0) + invalidate += edi->flags & mask; + edi->flags &= ~mask; + break; + } + case 1: //6CB79D + case 4: //6CB7C4 + //Set underground on, invalidate if it was off + invalidate += !(edi->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE); + edi->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; + break; + case 2: //6CB7EB + //Set track heights on, invalidate if off + invalidate += !(edi->flags & VIEWPORT_FLAG_TRACK_HEIGHTS); + edi->flags |= VIEWPORT_FLAG_TRACK_HEIGHTS; + break; + case 3: //6CB7B1 + case 5: //6CB7D8 + //Set underground off, invalidate if it was on + invalidate += edi->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; + edi->flags &= ~((uint16)VIEWPORT_FLAG_UNDERGROUND_INSIDE); + break; + } + if (invalidate != 0) window_invalidate(window); } } +/** + * Stores some info about the element pointed at, if requested for this particular type through the interaction mask. + * rct2: 0x00688697 + */ +void store_interaction_info(paint_struct *ps) +{ + if (RCT2_GLOBAL(0x0141F569, uint8) == 0) return; + + if (ps->sprite_type == VIEWPORT_INTERACTION_ITEM_NONE + || ps->sprite_type == 11 // 11 as a type seems to not exist, maybe part of the typo mentioned later on. + || ps->sprite_type > VIEWPORT_INTERACTION_ITEM_BANNER) return; + + uint16 mask; + if (ps->sprite_type == VIEWPORT_INTERACTION_ITEM_BANNER) + // I think CS made a typo here. Let's replicate the original behaviour. + mask = 1 << (ps->sprite_type - 3); + else + mask = 1 << (ps->sprite_type - 1); + + if (!(RCT2_GLOBAL(0x009AC154, uint16) & mask)) { + RCT2_GLOBAL(0x009AC148, uint8) = ps->sprite_type; + RCT2_GLOBAL(0x009AC149, uint8) = ps->var_29; + RCT2_GLOBAL(0x009AC14C, uint32) = ps->map_x; + RCT2_GLOBAL(0x009AC14E, uint32) = ps->map_y; + RCT2_GLOBAL(0x009AC150, rct_map_element*) = ps->mapElement; + } +} + +/** + * rct2: 0x0068862C + */ +void sub_68862C() +{ + rct_drawpixelinfo *dpi = RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*); + paint_struct *ps = RCT2_GLOBAL(0x00EE7884, paint_struct*), *old_ps, *next_ps, *attached_ps; + uint32 eax = 0xBBBBBBBB, ebx = 0xBBBBBBBB, ecx = 0xBBBBBBBB, edx = 0xBBBBBBBB, esi = 0xBBBBBBBB, edi = 0xBBBBBBBB, ebp = 0xBBBBBBBB; + + while ((ps = ps->var_24) != NULL) { + old_ps = ps; + + next_ps = ps; + while (next_ps != NULL) { + ps = next_ps; + ebx = ps->image_id; + ecx = ps->x; + edx = ps->y; + edi = (uint32)dpi; + ebp = (uint32)ps; + //sub_679023(ps->image_id, ps->x, ps->y, dpi); + RCT2_CALLFUNC_X(0x00679023, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + store_interaction_info(ps); + + next_ps = ps->var_20; + } + + attached_ps = ps->attached_ps; + while (attached_ps != NULL) { + esi = (uint32)attached_ps; + ebp = (uint32)ps; + ecx = (attached_ps->attached_x + ps->x) & 0xFFFF; + edx = (attached_ps->attached_y + ps->y) & 0xFFFF; + ebx = attached_ps->image_id; + //sub_679023(ebx, ecx, edx, dpi); + RCT2_CALLFUNC_X(0x00679023, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + store_interaction_info(ps); + + attached_ps = attached_ps->next_attached_ps; + } + + ps = old_ps; + } +} + /** * * rct2: 0x00685ADC @@ -1250,16 +1944,48 @@ void viewport_set_visibility(uint8 mode) * y: cx * z: bl * mapElement: edx + * viewport: edi */ -void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement) +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, sint16 *x, sint16 *y, int *interactionType, rct_map_element **mapElement, rct_viewport **viewport) { - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = screenX; - ebx = screenY; - edx = flags; - RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (x != NULL) *x = *((uint16*)&eax); - if (y != NULL) *y = *((uint16*)&ecx); - if (z != NULL) *z = *((uint8*)&ebx); - if (mapElement != NULL) *mapElement = (rct_map_element*)edx; + RCT2_GLOBAL(0x9AC154, uint16_t) = flags & 0xFFFF; + RCT2_GLOBAL(0x9AC148, uint8_t) = 0; + rct_window* window = window_find_from_point(screenX, screenY); + if (window != NULL && window->viewport != NULL) + { + rct_viewport* myviewport = window->viewport; + RCT2_GLOBAL(0x9AC138 + 4, int16_t) = screenX; + RCT2_GLOBAL(0x9AC138 + 6, int16_t) = screenY; + screenX -= (int)myviewport->x; + screenY -= (int)myviewport->y; + if (screenX >= 0 && screenX < (int)myviewport->width && screenY >= 0 && screenY < (int)myviewport->height) + { + screenX <<= myviewport->zoom; + screenY <<= myviewport->zoom; + screenX += (int)myviewport->view_x; + screenY += (int)myviewport->view_y; + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16_t) = myviewport->zoom; + screenX &= (0xFFFF << myviewport->zoom) & 0xFFFF; + screenY &= (0xFFFF << myviewport->zoom) & 0xFFFF; + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, int16_t) = screenX; + RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, int16_t) = screenY; + rct_drawpixelinfo* dpi = RCT2_ADDRESS(RCT2_ADDRESS_VIEWPORT_DPI, rct_drawpixelinfo); + dpi->y = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_Y, int16_t); + dpi->height = 1; + dpi->zoom_level = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_ZOOM, uint16_t); + dpi->x = RCT2_GLOBAL(RCT2_ADDRESS_VIEWPORT_PAINT_X, int16_t); + dpi->width = 1; + RCT2_GLOBAL(0xEE7880, uint32_t) = 0xF1A4CC; + RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*) = dpi; + sub_0x68615B(0xEE788C); + sub_0x68B6C2(); + sub_688217(); + sub_68862C(); + } + if (viewport != NULL) *viewport = myviewport; + } + if (interactionType != NULL) *interactionType = RCT2_GLOBAL(0x9AC148, uint8_t); + if (x != NULL) *x = RCT2_GLOBAL(0x9AC14C, int16_t); + if (y != NULL) *y = RCT2_GLOBAL(0x9AC14E, int16_t); + if (mapElement != NULL) *mapElement = RCT2_GLOBAL(0x9AC150, rct_map_element*); } \ No newline at end of file diff --git a/src/interface/viewport.h b/src/interface/viewport.h index 10dc86f7b5..7dcf3243fc 100644 --- a/src/interface/viewport.h +++ b/src/interface/viewport.h @@ -46,10 +46,11 @@ enum { enum { VIEWPORT_INTERACTION_ITEM_NONE, - - VIEWPORT_INTERACTION_ITEM_SPRITE = 2, + VIEWPORT_INTERACTION_ITEM_TERRAIN, + VIEWPORT_INTERACTION_ITEM_SPRITE, VIEWPORT_INTERACTION_ITEM_RIDE, - VIEWPORT_INTERACTION_ITEM_SCENERY = 5, + VIEWPORT_INTERACTION_ITEM_WATER, + VIEWPORT_INTERACTION_ITEM_SCENERY, VIEWPORT_INTERACTION_ITEM_FOOTPATH, VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM, VIEWPORT_INTERACTION_ITEM_PARK, @@ -59,6 +60,21 @@ enum { }; +enum { + VIEWPORT_INTERACTION_MASK_NONE = 0, + VIEWPORT_INTERACTION_MASK_TERRAIN = ~(1 << (VIEWPORT_INTERACTION_ITEM_TERRAIN - 1)), + VIEWPORT_INTERACTION_MASK_SPRITE = ~(1 << (VIEWPORT_INTERACTION_ITEM_SPRITE - 1)), + VIEWPORT_INTERACTION_MASK_RIDE = ~(1 << (VIEWPORT_INTERACTION_ITEM_RIDE - 1)), + VIEWPORT_INTERACTION_MASK_WATER = ~(1 << (VIEWPORT_INTERACTION_ITEM_WATER - 1)), + VIEWPORT_INTERACTION_MASK_SCENERY = ~(1 << (VIEWPORT_INTERACTION_ITEM_SCENERY - 1)), + VIEWPORT_INTERACTION_MASK_FOOTPATH = ~(1 << (VIEWPORT_INTERACTION_ITEM_FOOTPATH - 1)), + VIEWPORT_INTERACTION_MASK_FOOTPATH_ITEM = ~(1 << (VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM - 1)), + VIEWPORT_INTERACTION_MASK_PARK = ~(1 << (VIEWPORT_INTERACTION_ITEM_PARK - 1)), + VIEWPORT_INTERACTION_MASK_WALL = ~(1 << (VIEWPORT_INTERACTION_ITEM_WALL - 1)), + VIEWPORT_INTERACTION_MASK_LARGE_SCENERY = ~(1 << (VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY - 1)), + VIEWPORT_INTERACTION_MASK_BANNER = ~(1 << (VIEWPORT_INTERACTION_ITEM_BANNER - 2)), // Note the -2 for BANNER +}; + typedef struct { int type; int x; @@ -80,10 +96,14 @@ void viewport_create(rct_window *w, int x, int y, int width, int height, int zoo void viewport_update_pointers(); void viewport_update_position(rct_window *window); void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, int left, int top, int right, int bottom); +void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, int top, int right, int bottom); -void sub_689174(sint16* x, sint16* y, sint16 *z, uint8 curr_rotation); +void sub_689174(sint16* x, sint16* y, sint16 *z); -void screen_pos_to_map_pos(short *x, short *y); +rct_xy16 screen_coord_to_viewport_coord(rct_viewport *viewport, uint16 x, uint16 y); +rct_xy16 viewport_coord_to_map_coord(int x, int y, int z); +void sub_688972(int screenX, int screenY, sint16 *x, sint16 *y, rct_viewport **viewport); +void screen_pos_to_map_pos(sint16 *x, sint16 *y, int *direction); void show_gridlines(); void hide_gridlines(); @@ -93,7 +113,7 @@ void show_construction_rights(); void hide_construction_rights(); void viewport_set_visibility(uint8 mode); -void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement); +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, sint16 *x, sint16 *y, int *interactionType, rct_map_element **mapElement, rct_viewport **viewport); int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info *info); int viewport_interaction_left_over(int x, int y); @@ -101,5 +121,6 @@ int viewport_interaction_left_click(int x, int y); int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info *info); int viewport_interaction_right_over(int x, int y); int viewport_interaction_right_click(int x, int y); +void sub_68A15E(int screenX, int screenY, short *x, short *y, int *direction, rct_map_element **mapElement); #endif diff --git a/src/interface/viewport_interaction.c b/src/interface/viewport_interaction.c index 532e1067e2..3e0e049945 100644 --- a/src/interface/viewport_interaction.c +++ b/src/interface/viewport_interaction.c @@ -29,7 +29,9 @@ #include "../world/map.h" #include "../world/scenery.h" #include "../world/sprite.h" +#include "../input.h" #include "viewport.h" +#include "../cheats.h" static void viewport_interaction_remove_scenery(rct_map_element *mapElement, int x, int y); static void viewport_interaction_remove_footpath(rct_map_element *mapElement, int x, int y); @@ -58,7 +60,10 @@ int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info * if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; - get_map_coordinates_from_pos(x, y, 0xFF79, &info->x, &info->y, &info->type, &info->mapElement); + rct_xy16 mapCoord = { 0 }; + get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_SPRITE & VIEWPORT_INTERACTION_MASK_RIDE & VIEWPORT_INTERACTION_MASK_PARK, &mapCoord.x, &mapCoord.y, &info->type, &info->mapElement, NULL); + info->x = mapCoord.x; + info->y = mapCoord.y; mapElement = info->mapElement; sprite = (rct_sprite*)mapElement; @@ -67,7 +72,7 @@ int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info * switch (sprite->unknown.sprite_identifier) { case SPRITE_IDENTIFIER_VEHICLE: vehicle = &(sprite->vehicle); - if (vehicle->var_D6 != 255) + if (vehicle->ride_subtype != 255) vehicle_set_map_toolbar(vehicle); else info->type = VIEWPORT_INTERACTION_ITEM_NONE; @@ -81,8 +86,8 @@ int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info * ride_set_map_tooltip(mapElement); break; case VIEWPORT_INTERACTION_ITEM_PARK: - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); break; default: info->type = VIEWPORT_INTERACTION_ITEM_NONE; @@ -131,8 +136,17 @@ int viewport_interaction_left_click(int x, int y) case SPRITE_IDENTIFIER_PEEP: window_guest_open(info.peep); break; - case SPRITE_IDENTIFIER_FLOATING_TEXT: - balloon_pop(info.sprite); + case SPRITE_IDENTIFIER_MISC: + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) { + switch (info.sprite->unknown.misc_identifier) { + case SPRITE_MISC_BALLOON: + balloon_press(&info.sprite->balloon); + break; + case SPRITE_MISC_DUCK: + duck_press(&info.sprite->duck); + break; + } + } break; } return 1; @@ -169,7 +183,10 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; - get_map_coordinates_from_pos(x, y, 9, &info->x, &info->y, &info->type, &info->mapElement); + rct_xy16 mapCoord = { 0 }; + get_map_coordinates_from_pos(x, y, ~(VIEWPORT_INTERACTION_MASK_TERRAIN & VIEWPORT_INTERACTION_MASK_WATER), &mapCoord.x, &mapCoord.y, &info->type, &info->mapElement, NULL); + info->x = mapCoord.x; + info->y = mapCoord.y; mapElement = info->mapElement; sprite = (rct_sprite*)mapElement; @@ -190,7 +207,7 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info case VIEWPORT_INTERACTION_ITEM_RIDE: if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH) + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; ride = GET_RIDE(mapElement->properties.track.ride_index); @@ -199,13 +216,13 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1163; - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_ENTRANCE) { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = mapElement->properties.track.type == ENTRANCE_TYPE_RIDE_ENTRANCE ? 1335 : 1337; } else if (mapElement->properties.track.type == 1 || mapElement->properties.track.type == 2 || mapElement->properties.track.type == 3) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 1333; } else { - if (!sub_664F72(x, y, mapElement->base_height << 4)) + if (!map_is_location_owned(info->x, info->y, mapElement->base_height << 4)) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = ride->name; @@ -255,7 +272,7 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info return info->type; } - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & 0x48) != 0x48) + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & (INPUT_FLAG_6 | INPUT_FLAG_TOOL_ACTIVE)) != (INPUT_FLAG_6 | INPUT_FLAG_TOOL_ACTIVE)) if (window_find_by_class(WC_RIDE_CONSTRUCTION) == NULL && window_find_by_class(WC_FOOTPATH) == NULL) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; @@ -274,7 +291,7 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info return info->type; case VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM: - sceneryEntry = RCT2_ADDRESS(0x9ADA50, rct_scenery_entry*)[mapElement->properties.path.additions & 0x0F]; + sceneryEntry = g_pathBitSceneryEntries[(mapElement->properties.path.additions & 0x0F) - 1]; RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; if (mapElement->flags & 0x20) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 3124; @@ -285,10 +302,10 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info return info->type; case VIEWPORT_INTERACTION_ITEM_PARK: - if (!(RCT2_ADDRESS_SCREEN_FLAGS & SCREEN_FLAGS_SCENARIO_EDITOR)) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode) break; - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_ENTRANCE) + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) break; RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; @@ -324,6 +341,7 @@ int viewport_interaction_right_over(int x, int y) */ int viewport_interaction_right_click(int x, int y) { + rct_xy_element mapElement; viewport_interaction_info info; switch (viewport_interaction_get_item_right(x, y, &info)) { @@ -331,11 +349,14 @@ int viewport_interaction_right_click(int x, int y) return 0; case VIEWPORT_INTERACTION_ITEM_SPRITE: - if (info.mapElement->type == 0) - RCT2_CALLPROC_X(0x006B4857, info.x, 0, info.y, (int)info.sprite, 0, 0, 0); + if (info.sprite->unknown.sprite_identifier == SPRITE_IDENTIFIER_VEHICLE) + ride_construct(info.sprite->vehicle.ride); break; case VIEWPORT_INTERACTION_ITEM_RIDE: - ride_modify(info.mapElement, info.x, info.y); + mapElement.x = info.x; + mapElement.y = info.y; + mapElement.element = info.mapElement; + ride_modify(&mapElement); break; case VIEWPORT_INTERACTION_ITEM_SCENERY: viewport_interaction_remove_scenery(info.mapElement, info.x, info.y); @@ -395,15 +416,16 @@ static void viewport_interaction_remove_footpath(rct_map_element *mapElement, in w = window_find_by_class(WC_FOOTPATH); if (w != NULL) - sub_6A7831(); + footpath_provisional_update(); - mapElement2 = TILE_MAP_ELEMENT_POINTER((y / 32) * 256 + (x / 32)); + mapElement2 = map_get_first_element_at(x / 32, y / 32); do { - if ((mapElement2->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH && mapElement2->base_height == z) { + if (map_element_get_type(mapElement2) == MAP_ELEMENT_TYPE_PATH && mapElement2->base_height == z) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_FOOTPATH_FROM_HERE; footpath_remove(x, y, z, 1); + break; } - } while (!((mapElement2++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement2++)); } /** @@ -414,14 +436,14 @@ static void viewport_interaction_remove_footpath_item(rct_map_element *mapElemen { int type; - type = mapElement->properties.scenery.type >> 4; - if (mapElement->type & 0x80) + type = mapElement->properties.path.type >> 4; + if (mapElement->type & 1) type |= 0x80; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_THIS; game_do_command( x, - ((mapElement->properties.scenery.type & 7) << 8) | 1, + ((mapElement->properties.path.type & 7) << 8) | 1, y, (type << 8) | mapElement->base_height, GAME_COMMAND_PLACE_PATH, @@ -436,7 +458,19 @@ static void viewport_interaction_remove_footpath_item(rct_map_element *mapElemen */ static void viewport_interaction_remove_park_entrance(rct_map_element *mapElement, int x, int y) { - RCT2_CALLPROC_X(0x00666C0E, x, 0, y, (int)mapElement, 0, 0, 0); + int rotation = (mapElement->type + 1) & 3; + switch (mapElement->properties.entrance.index & 0x0F) { + case 1: + x += TileDirectionDelta[rotation].x; + y += TileDirectionDelta[rotation].y; + break; + case 2: + x -= TileDirectionDelta[rotation].x; + y -= TileDirectionDelta[rotation].y; + break; + } + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_THIS; + game_do_command(x, GAME_COMMAND_FLAG_APPLY, y, mapElement->base_height / 2, GAME_COMMAND_REMOVE_PARK_ENTRANCE, 0, 0); } /** @@ -447,14 +481,14 @@ static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, i { rct_scenery_entry* sceneryEntry; - sceneryEntry = g_wallSceneryEntries[mapElement->properties.fence.slope]; + sceneryEntry = g_wallSceneryEntries[mapElement->properties.fence.type]; if (sceneryEntry->wall.var_0D != 0xFF){ window_sign_small_open(mapElement->properties.fence.item[0]); } else { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1158; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = STR_CANT_REMOVE_THIS; game_do_command( x, - 1, + GAME_COMMAND_FLAG_APPLY, y, (mapElement->type & 0x3) | (mapElement->base_height << 8), GAME_COMMAND_REMOVE_FENCE, @@ -470,12 +504,9 @@ static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, i */ static void viewport_interaction_remove_large_scenery(rct_map_element *mapElement, int x, int y) { - int ebx; rct_scenery_entry* sceneryEntry; - ebx = mapElement->properties.scenerymultiple.type; - ebx |= (mapElement->properties.scenerymultiple.index & 0x3) << 8; - sceneryEntry = g_largeSceneryEntries[ebx]; + sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK]; if (sceneryEntry->large_scenery.var_11 != 0xFF){ int id = (mapElement->type & 0xC0) | @@ -488,8 +519,8 @@ static void viewport_interaction_remove_large_scenery(rct_map_element *mapElemen x, 1 | ((mapElement->type & 0x3) << 8), y, - mapElement->base_height | ((mapElement->properties.scenerymultiple.index >> 2) << 8), - GAME_COMMAND_44, + mapElement->base_height | ((mapElement->properties.scenerymultiple.type >> 10) << 8), + GAME_COMMAND_REMOVE_LARGE_SCENERY, 0, 0 ); @@ -518,7 +549,7 @@ static rct_peep *viewport_interaction_get_closest_peep(int x, int y, int maxDist closestPeep = NULL; closestDistance = 0xFFFF; FOR_ALL_PEEPS(spriteIndex, peep) { - if (peep->sprite_left == 0x8000) + if (peep->sprite_left == (sint16)0x8000) continue; distance = @@ -534,4 +565,73 @@ static rct_peep *viewport_interaction_get_closest_peep(int x, int y, int maxDist } return closestPeep; -} \ No newline at end of file +} + +/** + * + * rct2: 0x0068A15E + */ +void sub_68A15E(int screenX, int screenY, short *x, short *y, int *direction, rct_map_element **mapElement) +{ + sint16 my_x, my_y; + int z, interactionType; + rct_map_element *myMapElement; + rct_viewport *viewport; + get_map_coordinates_from_pos(screenX, screenY, VIEWPORT_INTERACTION_MASK_TERRAIN & VIEWPORT_INTERACTION_MASK_WATER, &my_x, &my_y, &interactionType, &myMapElement, &viewport); + + if (interactionType == VIEWPORT_INTERACTION_ITEM_NONE) { + *x = 0x8000; + return; + } + + RCT2_GLOBAL(0x00F1AD3E, uint8) = interactionType; + RCT2_GLOBAL(0x00F1AD30, rct_map_element*) = myMapElement; + + if (interactionType == VIEWPORT_INTERACTION_ITEM_WATER) { + z = myMapElement->properties.surface.terrain; + z = (z & MAP_ELEMENT_WATER_HEIGHT_MASK) << 4; + } + + RCT2_GLOBAL(0x00F1AD3C, uint16) = z; + RCT2_GLOBAL(0x00F1AD34, sint16) = my_x; + RCT2_GLOBAL(0x00F1AD36, sint16) = my_y; + RCT2_GLOBAL(0x00F1AD38, sint16) = my_x + 31; + RCT2_GLOBAL(0x00F1AD3A, sint16) = my_y + 31; + + rct_xy16 start_vp_pos = screen_coord_to_viewport_coord(viewport, screenX, screenY); + rct_xy16 map_pos = { my_x + 16, my_y + 16 }; + + for (int i = 0; i < 5; i++) { + if (RCT2_GLOBAL(0x00F1AD3E, uint8) != 4) { + z = map_element_height(map_pos.x, map_pos.y); + } else { + z = RCT2_GLOBAL(0x00F1AD3C, uint16); + } + map_pos = viewport_coord_to_map_coord(start_vp_pos.x, start_vp_pos.y, z); + map_pos.x = clamp(RCT2_GLOBAL(0x00F1AD34, sint16), map_pos.x, RCT2_GLOBAL(0x00F1AD38, sint16)); + map_pos.y = clamp(RCT2_GLOBAL(0x00F1AD36, sint16), map_pos.y, RCT2_GLOBAL(0x00F1AD3A, sint16)); + } + + // Determine to which edge the cursor is closest + int myDirection; + int mod_x = map_pos.x & 0x1F; + int mod_y = map_pos.y & 0x1F; + if (mod_x < mod_y) { + if (mod_x + mod_y < 32) { + myDirection = 0; + } else { + myDirection = 1; + } + } else { + if (mod_x + mod_y < 32) { + myDirection = 3; + } else { + myDirection = 2; + } + } + + *x = map_pos.x & ~0x1F; + *y = map_pos.y & ~0x1F; + if (direction != NULL) *direction = myDirection; + if (mapElement != NULL) *mapElement = myMapElement; +} diff --git a/src/interface/widget.c b/src/interface/widget.c index b4c6ac0072..87472e630f 100644 --- a/src/interface/widget.c +++ b/src/interface/widget.c @@ -24,6 +24,8 @@ #include "../sprites.h" #include "widget.h" #include "window.h" +#include "../platform/platform.h" +#include "../localisation/localisation.h" static void widget_frame_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_resize_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); @@ -35,6 +37,7 @@ static void widget_text_unknown(rct_drawpixelinfo *dpi, rct_window *w, int widge static void widget_text(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_text_inset(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_text_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); +static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_groupbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_checkbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); @@ -160,6 +163,9 @@ void widget_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) break; case WWT_25: break; + case WWT_TEXT_BOX: + widget_text_box_draw(dpi, w, widgetIndex); + break; } } @@ -200,7 +206,7 @@ static void widget_frame_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetI // Draw the resize sprite at the bottom right corner l = w->x + widget->right - 18; t = w->y + widget->bottom - 18; - gfx_draw_sprite(dpi, SPR_RESIZE | 0x20000000 | (colour << 19), l, t, 0); + gfx_draw_sprite(dpi, SPR_RESIZE | 0x20000000 | ((colour & 0x7F) << 19), l, t, 0); } /** @@ -237,7 +243,7 @@ static void widget_resize_draw(rct_drawpixelinfo *dpi, rct_window *w, int widget // Draw the resize sprite at the bottom right corner l = w->x + widget->right - 18; t = w->y + widget->bottom - 18; - gfx_draw_sprite(dpi, SPR_RESIZE | 0x20000000 | (colour << 19), l, t, 0); + gfx_draw_sprite(dpi, SPR_RESIZE | 0x20000000 | ((colour & 0x7F) << 19), l, t, 0); } /** @@ -316,7 +322,7 @@ static void widget_tab_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetInd b = w->y + widget->bottom; // Get the colour and image - colour = w->colours[widget->colour]; + colour = w->colours[widget->colour] & 0x7F; image = widget->image + 2; // Draw coloured image @@ -570,7 +576,7 @@ static void widget_groupbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg if (widget_is_disabled(w, widgetIndex)) colour |= 0x40; gfx_draw_string_left(dpi, widget->image, (void*)0x013CE952, colour, l, t); - textRight = gLastDrawStringX + 1; + textRight = l + gfx_get_string_width((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER) + 1; } // Border @@ -651,7 +657,12 @@ static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widge press |= 0x80; gfx_fill_rect_inset(dpi, l, t, r, b, colour, press); - gfx_fill_rect(dpi, l + 1, t + 1, r - 1, b - 1, 0x2000000 | 47); + + // Black caption bars look slightly green, this fixes that + if (colour == 0) + gfx_fill_rect(dpi, l + 1, t + 1, r - 1, b - 1, *((char*)(0x0141FC46 + (colour * 8)))); + else + gfx_fill_rect(dpi, l + 1, t + 1, r - 1, b - 1, 0x2000000 | 47); } // Draw text @@ -793,13 +804,15 @@ static void widget_scroll_draw(rct_drawpixelinfo *dpi, rct_window *w, int widget r--; b--; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = 0xE0; + // Horizontal scrollbar if (scroll->flags & HSCROLLBAR_VISIBLE) - widget_hscrollbar_draw(dpi, scroll, l, b - 10, (scroll->flags & VSCROLLBAR_VISIBLE ? r - 10 : r), b, colour); + widget_hscrollbar_draw(dpi, scroll, l, b - 10, (scroll->flags & VSCROLLBAR_VISIBLE ? r - 11 : r), b, colour); // Vertical scrollbar if (scroll->flags & VSCROLLBAR_VISIBLE) - widget_vscrollbar_draw(dpi, scroll, r - 10, t, r, (scroll->flags & HSCROLLBAR_VISIBLE ? b - 10 : b), colour); + widget_vscrollbar_draw(dpi, scroll, r - 10, t, r, (scroll->flags & HSCROLLBAR_VISIBLE ? b - 11 : b), colour); // Contents if (scroll->flags & HSCROLLBAR_VISIBLE) @@ -830,11 +843,12 @@ static void widget_scroll_draw(rct_drawpixelinfo *dpi, rct_window *w, int widget // Draw the scroll contents if (scroll_dpi.width > 0 && scroll_dpi.height > 0) - RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_PAINT], 0, 0, 0, 0, (int)w, (int)&scroll_dpi, 0); + window_event_scroll_paint_call(w, &scroll_dpi, scrollIndex); } static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, int l, int t, int r, int b, int colour) { + colour &= 0x7F; // Trough gfx_fill_rect(dpi, l + 10, t, r - 10, b, *((char*)(0x0141FC4B + (colour * 8)))); gfx_fill_rect(dpi, l + 10, t, r - 10, b, 0x1000000 | *((char*)(0x0141FC47 + (colour * 8)))); @@ -860,6 +874,7 @@ static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i static void widget_vscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, int l, int t, int r, int b, int colour) { + colour &= 0x7F; // Trough gfx_fill_rect(dpi, l, t + 10, r, b - 10, *((char*)(0x0141FC4B + (colour * 8)))); gfx_fill_rect(dpi, l, t + 10, r, b - 10, 0x1000000 | *((char*)(0x0141FC47 + (colour * 8)))); @@ -880,7 +895,7 @@ static void widget_vscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i // Down button gfx_fill_rect_inset(dpi, l, b - 9, r, b, colour, (scroll->flags & VSCROLLBAR_DOWN_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED69, 0, l + 1, b - 8); + gfx_draw_string(dpi, (char*)0x009DED69, 0, l + 1, b - 9); } /** @@ -907,7 +922,7 @@ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetI b = w->y + widget->bottom; // Get the colour - colour = w->colours[widget->colour]; + colour = w->colours[widget->colour] & 0x7F; if (widget->type == WWT_4 || widget->type == WWT_COLORBTN || widget->type == WWT_TRNBTN || widget->type == WWT_TAB) if (widget_is_pressed(w, widgetIndex) || widget_is_active_tool(w, widgetIndex)) @@ -1113,3 +1128,86 @@ void widget_scroll_get_part(rct_window *w, rct_widget* widget, int x, int y, int } } } + +void widget_set_checkbox_value(rct_window *w, int widgetIndex, int value) +{ + if (value) + w->pressed_widgets |= (1ULL << widgetIndex); + else + w->pressed_widgets &= ~(1ULL << widgetIndex); +} + +static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) +{ + rct_widget* widget; + int l, t, r, b; + uint8 colour; + int no_lines = 0; + int font_height = 0; + char wrapped_string[512]; + + // Get the widget + widget = &w->widgets[widgetIndex]; + + // Resolve the absolute ltrb + l = w->x + widget->left; + t = w->y + widget->top; + r = w->x + widget->right; + b = w->y + widget->bottom; + + // Get the colour + colour = w->colours[widget->colour]; + + + bool active = w->classification == gCurrentTextBox.window.classification && + w->number == gCurrentTextBox.window.number && + widgetIndex == gCurrentTextBox.widget_index; + + //gfx_fill_rect_inset(dpi, l, t, r, b, colour, 0x20 | (!active ? 0x40 : 0x00)); + gfx_fill_rect_inset(dpi, l, t, r, b, colour, 0x60); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + if (!active) { + + if (w->widgets[widgetIndex].image != 0) { + strcpy(wrapped_string, (char*)w->widgets[widgetIndex].image); + gfx_wrap_string(wrapped_string, r - l - 5, &no_lines, &font_height); + gfx_draw_string(dpi, wrapped_string, w->colours[1], l + 2, t); + } + return; + } + + + strcpy(wrapped_string, gTextBoxInput); + + // String length needs to add 12 either side of box + // +13 for cursor when max length. + gfx_wrap_string(wrapped_string, r - l - 5 - 6, &no_lines, &font_height); + + + gfx_draw_string(dpi, wrapped_string, w->colours[1], l + 2, t); + + + int string_length = get_string_length(wrapped_string); + + // Make a copy of the string for measuring the width. + char temp_string[512] = { 0 }; + memcpy(temp_string, wrapped_string, min(string_length, gTextInputCursorPosition)); + int cur_x = l + gfx_get_string_width(temp_string) + 3; + + int width = 6; + if ((uint32)gTextInputCursorPosition < strlen(gTextBoxInput)){ + // Make a new 1 character wide string for measuring the width + // of the character that the cursor is under. + temp_string[1] = '\0'; + temp_string[0] = gTextBoxInput[gTextInputCursorPosition]; + width = max(gfx_get_string_width(temp_string) - 2, 4); + } + + if (gTextBoxFrameNo <= 15){ + uint8 colour = RCT2_ADDRESS(0x0141FC48, uint8)[w->colours[1] * 8]; + gfx_fill_rect(dpi, cur_x, t + 9, cur_x + width, t + 9, colour + 5); + } +} diff --git a/src/interface/widget.h b/src/interface/widget.h index f0b044a542..ad7e4d0b35 100644 --- a/src/interface/widget.h +++ b/src/interface/widget.h @@ -50,6 +50,7 @@ typedef enum { WWT_CHECKBOX = 23, WWT_24, WWT_25, + WWT_TEXT_BOX = 27, WWT_LAST = 26, } WINDOW_WIDGET_TYPES; #define WIDGETS_END WWT_LAST, 0, 0, 0, 0, 0, 0, 0 @@ -63,4 +64,7 @@ int widget_is_pressed(rct_window *w, int widgetIndex); int widget_is_highlighted(rct_window *w, int widgetIndex); int widget_is_active_tool(rct_window *w, int widgetIndex); void widget_scroll_get_part(rct_window *w, rct_widget* widget, int x, int y, int *output_x, int *output_y, int *output_scroll_area, int *scroll_id); + +void widget_set_checkbox_value(rct_window *w, int widgetIndex, int value); + #endif diff --git a/src/interface/window.c b/src/interface/window.c index c94ebff4e1..2c210a78ac 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -23,12 +23,14 @@ #include "../game.h" #include "../drawing/drawing.h" #include "../input.h" -#include "../platform/osinterface.h" +#include "../platform/platform.h" #include "../world/map.h" #include "../world/sprite.h" #include "widget.h" #include "window.h" #include "viewport.h" +#include "../localisation/string_ids.h" +#include "../localisation/localisation.h" #define RCT2_FIRST_WINDOW (RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window)) #define RCT2_LAST_WINDOW (RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*) - 1) @@ -38,28 +40,36 @@ rct_window* g_window_list = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window); +uint8 TextInputDescriptionArgs[8]; +widget_identifier gCurrentTextBox = { { 255, 0 }, 0 }; +char gTextBoxInput[512] = { 0 }; +int gMaxTextBoxInputLength = 0; +int gTextBoxFrameNo = 0; +bool gUsingWidgetTextBox = 0; + // converted from uint16 values at 0x009A41EC - 0x009A4230 // these are percentage coordinates of the viewport to center to, if a window is obscuring a location, the next is tried float window_scroll_locations[][2] = { - 0.5f, 0.5f, - 0.75f, 0.5f, - 0.25f, 0.5f, - 0.5f, 0.75f, - 0.5f, 0.25f, - 0.75f, 0.75f, - 0.75f, 0.25f, - 0.25f, 0.75f, - 0.25f, 0.25f, - 0.125f, 0.5f, - 0.875f, 0.5f, - 0.5f, 0.125f, - 0.5f, 0.875f, - 0.875f, 0.125f, - 0.875f, 0.875f, - 0.125f, 0.875f, - 0.125f, 0.125f, + {0.5f, 0.5f}, + {0.75f, 0.5f}, + {0.25f, 0.5f}, + {0.5f, 0.75f}, + {0.5f, 0.25f}, + {0.75f, 0.75f}, + {0.75f, 0.25f}, + {0.25f, 0.75f}, + {0.25f, 0.25f}, + {0.125f, 0.5f}, + {0.875f, 0.5f}, + {0.5f, 0.125f}, + {0.5f, 0.875f}, + {0.875f, 0.125f}, + {0.875f, 0.875f}, + {0.125f, 0.875f}, + {0.125f, 0.125f}, }; +static bool sub_6EA95D(int x, int y, int width, int height); static void window_all_wheel_input(); static int window_draw_split(rct_window *w, int left, int top, int right, int bottom); @@ -128,27 +138,7 @@ rct_widget *window_get_scroll_widget(rct_window *w, int scrollIndex) return NULL; } -static void RCT2_CALLPROC_WE_UPDATE(int address, rct_window* w) -{ - #ifdef _MSC_VER - __asm { - push address - push w - mov esi, w - call[esp + 4] - add esp, 8 - } - #else - __asm__ ( "\ - push %[address]\n\ - mov eax, %[w] \n\ - push eax \n\ - mov esi, %[w] \n\ - call [esp+4] \n\ - add esp, 8 \n\ - " : [address] "+m" (address), [w] "+m" (w) : : "eax", "esi" ); - #endif -} + /** * * rct2: 0x006ED7B0 @@ -158,9 +148,9 @@ void window_dispatch_update_all() rct_window *w; RCT2_GLOBAL(0x01423604, sint32)++; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16)++; + //RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16)++; for (w = RCT2_LAST_WINDOW; w >= g_window_list; w--) - RCT2_CALLPROC_WE_UPDATE(w->event_handlers[WE_UPDATE], w); + window_event_update_call(w); RCT2_CALLPROC_EBPSAFE(0x006EE411); // handle_text_input } @@ -174,9 +164,6 @@ void window_update_all() rct_window* w; RCT2_GLOBAL(0x009E3CD8, sint32)++; - // if (RCT2_GLOBAL(0x009E3CD8, sint32) == 224 && RCT2_GLOBAL(0x009ABDF2, sint8) != 0) - // RCT2_CALLPROC(0x004067E3); // ddwindow_move_to_top_corner - if (RCT2_GLOBAL(0x009ABDF2, sint8) == 0) return; @@ -191,7 +178,7 @@ void window_update_all() if (RCT2_GLOBAL(0x009DEB7C, sint16) >= 1000) { RCT2_GLOBAL(0x009DEB7C, sint16) = 0; for (w = RCT2_LAST_WINDOW; w >= g_window_list; w--) - RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_07], 0, 0, 0, 0, (int) w, 0, 0); + window_event_unknown_07_call(w); } // Border flash invalidation @@ -203,7 +190,6 @@ void window_update_all() } } - // RCT2_CALLPROC_X(0x006E7868, 0, 0, 0, 0, 0, RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo), 0); // process_mouse_wheel_input(); window_all_wheel_input(); } @@ -319,7 +305,7 @@ static void window_all_wheel_input() w = window_find_from_point(gCursorState.x, gCursorState.y); if (w != NULL) { // Check if main window - if (w->classification == WC_MAIN_WINDOW) { + if (w->classification == WC_MAIN_WINDOW || w->classification == WC_VIEWPORT) { window_viewport_wheel_input(w, wheel); return; } @@ -417,7 +403,7 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han w->enabled_widgets = 0; w->disabled_widgets = 0; w->pressed_widgets = 0; - w->var_020 = 0; + w->hold_down_widgets = 0; w->viewport_focus_coordinates.var_480 = 0; w->viewport_focus_coordinates.x = 0; w->viewport_focus_coordinates.y = 0; @@ -436,6 +422,76 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han return w; } +/** + * + * rct2: 0x006EA934 + * + * @param x (dx) + * @param y (ax) + * @param width (bx) + * @param height (cx) + */ +static bool sub_6EA8EC(int x, int y, int width, int height) +{ + uint16 screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + uint16 screenHeight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); + int unk; + + unk = -(width / 4); + if (x < unk) return false; + unk = screenWidth + (unk * 2); + if (x > unk) return false; + if (y < 28) return false; + unk = screenHeight - (height / 4); + if (y > unk) return false; + return sub_6EA95D(x, y, width, height); +} + +/** + * + * rct2: 0x006EA934 + * + * @param x (dx) + * @param y (ax) + * @param width (bx) + * @param height (cx) + */ +static bool sub_6EA934(int x, int y, int width, int height) +{ + if (x < 0) return false; + if (y < 28) return false; + if (x + width > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)) return false; + if (y + height > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)) return false; + return sub_6EA95D(x, y, width, height); +} + +/** + * + * rct2: 0x006EA934 + * + * @param x (dx) + * @param y (ax) + * @param width (bx) + * @param height (cx) + */ +static bool sub_6EA95D(int x, int y, int width, int height) +{ + rct_window *w; + + for (w = g_window_list; w < RCT2_LAST_WINDOW; w++) { + if (w->flags & WF_STICK_TO_BACK) + continue; + + if (x + width <= w->x) continue; + if (x >= w->x + w->width) continue; + if (y + height <= w->y) continue; + if (y >= w->y + w->height) continue; + return false; + } + + return true; +} + /** * Opens a new window, supposedly automatically positioned * rct2: 0x006EA9B1 @@ -448,13 +504,133 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han */ rct_window *window_create_auto_pos(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags) { - int eax, ebx, ecx, edx, esi, edi, ebp; + rct_window *w; + int x, y; - ebx = (height << 16) | width; - ecx = (flags << 8) | cls; - edx = (int)event_handlers; - RCT2_CALLFUNC_X(0x006EA9B1, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return (rct_window*)esi; + uint16 screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + uint16 screenHeight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); + + if (cls & 0x80) { + cls &= ~0x80; + w = window_find_by_number(RCT2_GLOBAL(0x0013CE928, rct_windowclass), RCT2_GLOBAL(0x0013CE92A, rct_windownumber)); + if (w != NULL) { + if (w->x > -60 && w->x < RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 20) { + if (w->y < RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 20) { + x = w->x; + if (w->x + width > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)) + x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 20 - width; + y = w->y; + return window_create(x + 10, y + 10, width, height, event_handlers, cls, flags); + } + } + } + } + + // Place window in an empty corner of the screen + x = 0; + y = 30; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = screenWidth - width; + y = 30; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = 0; + y = screenHeight - 34 - height; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = screenWidth - width; + y = screenHeight - 34 - height; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + // Place window next to another + for (w = g_window_list; w < RCT2_LAST_WINDOW; w++) { + if (w->flags & WF_STICK_TO_BACK) + continue; + + x = w->x + w->width + 2; + y = w->y; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = w->x - w->width - 2; + y = w->y; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = w->x; + y = w->y + w->height + 2; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = w->x; + y = w->y - w->height - 2; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = w->x + w->width + 2; + y = w->y - w->height - 2; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = w->x - w->width - 2; + y = w->y - w->height - 2; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = w->x + w->width + 2; + y = w->y + w->height + 2; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + + x = w->x - w->width - 2; + y = w->y + w->height + 2; + if (sub_6EA934(x, y, width, height)) goto foundSpace; + } + + // Overlap + for (w = g_window_list; w < RCT2_LAST_WINDOW; w++) { + if (w->flags & WF_STICK_TO_BACK) + continue; + + x = w->x + w->width + 2; + y = w->y; + if (sub_6EA8EC(x, y, width, height)) goto foundSpace; + + x = w->x - w->width - 2; + y = w->y; + if (sub_6EA8EC(x, y, width, height)) goto foundSpace; + + x = w->x; + y = w->y + w->height + 2; + if (sub_6EA8EC(x, y, width, height)) goto foundSpace; + + x = w->x; + y = w->y - w->height - 2; + if (sub_6EA8EC(x, y, width, height)) goto foundSpace; + } + + // Cascade + x = 0; + y = 30; + for (w = g_window_list; w < RCT2_LAST_WINDOW; w++) { + if (x != w->x || y != w->y) + continue; + + x += 5; + y += 5; + } + + // Clamp to inside the screen +foundSpace: + if (x < 0) + x = x; + if (x + width > screenWidth) + x = screenWidth - width; + + return window_create(x, y, width, height, event_handlers, cls, flags); +} + +rct_window *window_create_centred(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags) +{ + int x, y; + + x = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width) / 2; + y = max(28, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height) / 2); + return window_create(x, y, width, height, event_handlers, cls, flags); } /** @@ -470,10 +646,16 @@ void window_close(rct_window* window) if (window == NULL) return; - // Call close event of window - RCT2_CALLPROC_X(window->event_handlers[WE_CLOSE], 0, 0, 0, 0, (int)window, 0, 0); + // Make a copy of the window class and number incase + // the window order is changed by the close event. + rct_windowclass cls = window->classification; + rct_windownumber number = window->number; - window = window_find_by_number(window->classification, window->number); + window_event_close_call(window); + + window = window_find_by_number(cls, number); + if (window == NULL) + return; // Remove viewport if (window->viewport != NULL) { @@ -578,7 +760,7 @@ void window_close_top() if (RCT2_GLOBAL(0x0141F570, uint8) != 1) return; - for (w = g_window_list; w < RCT2_LAST_WINDOW; w++) { + for (w = RCT2_NEW_WINDOW - 1; w >= g_window_list; w--) { if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))) { window_close(w); return; @@ -604,6 +786,19 @@ void window_close_all() { } } +void window_close_all_except_class(rct_windowclass cls) { + rct_window* w; + + window_close_by_class(WC_DROPDOWN); + + for (w = g_window_list; w < RCT2_LAST_WINDOW; w++){ + if (w->classification != cls && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))) { + window_close(w); + w = g_window_list; + } + } +} + /** * * rct2: 0x006EA845 @@ -646,7 +841,7 @@ int window_find_widget_from_point(rct_window *w, int x, int y) int i, widget_index; // Invalidate the window - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); // Find the widget at point x, y widget_index = -1; @@ -719,6 +914,17 @@ void window_invalidate_by_number(rct_windowclass cls, rct_windownumber number) window_invalidate(w); } +/** + * Invalidates all windows. + */ +void window_invalidate_all() +{ + rct_window* w; + + for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) + window_invalidate(w); +} + /** * Invalidates the specified widget of a window. * rct2: 0x006EC402 @@ -811,19 +1017,44 @@ void window_init_scroll_widgets(rct_window *w) */ void window_update_scroll_widgets(rct_window *w) { - RCT2_CALLPROC_X(0x006EAE4E, 0, 0, 0, 0, (int)w, 0, 0); -} + int widgetIndex, scrollIndex, width, height, scrollPositionChanged; + rct_scroll *scroll; + rct_widget *widget; -int window_get_scroll_size(rct_window *w, int scrollIndex, int *width, int *height) -{ - rct_widget *widget = window_get_scroll_widget(w, scrollIndex); - int widgetIndex = window_get_widget_index(w, widget); + widgetIndex = 0; + scrollIndex = 0; + for (widget = w->widgets; widget->type != WWT_LAST; widget++, widgetIndex++) { + if (widget->type != WWT_SCROLL) + continue; - int eax = 0, ebx = scrollIndex * sizeof(rct_scroll), ecx = 0, edx = 0, esi = (int)w, edi = widgetIndex * sizeof(rct_widget), ebp = 0; - RCT2_CALLFUNC_X(w->event_handlers[WE_SCROLL_GETSIZE], & eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *width = ecx; - *height = edx; - return 1; + scroll = &w->scrolls[scrollIndex]; + window_get_scroll_size(w, scrollIndex, &width, &height); + if (height == 0){ + scroll->v_top = 0; + } + else if (width == 0){ + scroll->h_left = 0; + } + width++; + height++; + + scrollPositionChanged = 0; + if ((widget->image & 1) && width != scroll->h_right) { + scrollPositionChanged = 1; + scroll->h_right = width; + } + + if ((widget->image & 2) && height != scroll->v_bottom) { + scrollPositionChanged = 1; + scroll->v_bottom = height; + } + + if (scrollPositionChanged) { + widget_scroll_update_thumbs(w, widgetIndex); + window_invalidate(w); + } + scrollIndex++; + } } int window_get_scroll_data_index(rct_window *w, int widget_index) @@ -1002,7 +1233,7 @@ rct_window *window_get_main() /** * Based on - * rct2: 0x696ee9 & 0x66842F + * rct2: 0x696ee9 & 0x66842F & 0x006AF3B3 * */ void window_scroll_to_viewport(rct_window *w) @@ -1113,14 +1344,24 @@ void window_scroll_to_location(rct_window *w, int x, int y, int z) } } +/** + * + * rct2: 0x00688956 + */ +void sub_688956() +{ + rct_window *w; + + for (w = RCT2_NEW_WINDOW - 1; w >= g_window_list; w--) + window_event_unknown_14_call(w); +} + /** * * rct2: 0x0068881A */ void window_rotate_camera(rct_window *w) { - //RCT2_CALLPROC_X(0x0068881A, 0, 0, 0, 0, (int)w, 0, 0); - rct_viewport *viewport = w->viewport; if (viewport == NULL) return; @@ -1129,12 +1370,9 @@ void window_rotate_camera(rct_window *w) sint16 y = (viewport->height >> 1) + viewport->y; sint16 z; - uint8 rot = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); - - int ecx, edx, esi, edi = (int)viewport, ebp; //has something to do with checking if middle of the viewport is obstructed - RCT2_CALLFUNC_X(0x00688972, (int*)&x, (int*)&y, &ecx, &edx, &esi, &edi, &ebp); - rct_viewport *other = (rct_viewport*)edi; + rct_viewport *other; + sub_688972(x, y, &x, &y, &other); // other != viewport probably triggers on viewports in ride or guest window? // x is 0x8000 if middle of viewport is obstructed by another window? @@ -1142,12 +1380,12 @@ void window_rotate_camera(rct_window *w) x = (viewport->view_width >> 1) + viewport->view_x; y = (viewport->view_height >> 1) + viewport->view_y; - sub_689174(&x, &y, &z, rot); + sub_689174(&x, &y, &z); } else { z = map_element_height(x, y); } - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = (rot + 1) % 4; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) + 1) % 4; int new_x, new_y; center_2d_coordinates(x, y, z, &new_x, &new_y, viewport); @@ -1159,9 +1397,40 @@ void window_rotate_camera(rct_window *w) window_invalidate(w); - RCT2_CALLPROC_EBPSAFE(0x00688956); + sub_688956(); + reset_all_sprite_quadrant_placements(); +} - sub_69E9A7(); +void window_zoom_set(rct_window *w, int zoomLevel) +{ + rct_viewport* v = w->viewport; + + zoomLevel = clamp(0, zoomLevel, 3); + if (v->zoom == zoomLevel) + return; + + // Zoom in + while (v->zoom > zoomLevel) { + v->zoom--; + w->saved_view_x += v->view_width / 4; + w->saved_view_y += v->view_height / 4; + v->view_width /= 2; + v->view_height /= 2; + } + + // Zoom out + while (v->zoom < zoomLevel) { + v->zoom++; + w->saved_view_x -= v->view_width / 2; + w->saved_view_y -= v->view_height / 2; + v->view_width *= 2; + v->view_height *= 2; + } + + // HACK: Prevents the redraw from failing when there is + // a window on top of the viewport. + window_bring_to_front(w); + window_invalidate(w); } /** @@ -1170,22 +1439,7 @@ void window_rotate_camera(rct_window *w) */ void window_zoom_in(rct_window *w) { - rct_viewport* v = w->viewport; - - // Prevent zooming more than possible. - if (v->zoom <= 0) { - return; - } - - v->zoom--; - - v->view_width /= 2; - v->view_height /= 2; - - w->saved_view_x += v->view_width >> 1; - w->saved_view_y += v->view_height >> 1; - - window_invalidate(w); + window_zoom_set(w, w->viewport->zoom - 1); } /** @@ -1194,25 +1448,7 @@ void window_zoom_in(rct_window *w) */ void window_zoom_out(rct_window *w) { - rct_viewport* v = w->viewport; - - // Prevent zooming more than possible. - if (v->zoom >= 3) { - return; - } - - v->zoom++; - - int width = v->view_width; - int height = v->view_height; - - v->view_width *= 2; - v->view_height *= 2; - - w->saved_view_x -= width / 2; - w->saved_view_y -= height >> 1; - - window_invalidate(w); + window_zoom_set(w, w->viewport->zoom + 1); } /** @@ -1239,9 +1475,6 @@ void window_draw(rct_window *w, int left, int top, int right, int bottom) rct_drawpixelinfo *dpi, copy; int overflow; - // RCT2_CALLPROC_X(0x006E756C, left, top, 0, right, w, 0, bottom); - // return; - // Split window into only the regions that require drawing if (window_draw_split(w, left, top, right, bottom)) return; @@ -1305,17 +1538,17 @@ void window_draw(rct_window *w, int left, int top, int right, int bottom) RCT2_GLOBAL(0x01420070, sint32) = v->x; + // Invalidate modifies the window colours so first get the correct + // colour before setting the global variables for the string painting + window_event_invalidate_call(v); + // Text colouring RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8) = v->colours[0] & 0x7F; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8) = v->colours[1] & 0x7F; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8) = v->colours[2] & 0x7F; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_4, uint8) = v->colours[3] & 0x7F; - // Invalidate the window - RCT2_CALLPROC_X(v->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)v, 0, 0); - - // Paint the window - RCT2_CALLPROC_X(v->event_handlers[WE_PAINT], 0, 0, 0, 0, (int)v, (int)dpi, 0); + window_event_paint_call(v, dpi); } } @@ -1376,9 +1609,6 @@ void window_draw_widgets(rct_window *w, rct_drawpixelinfo *dpi) rct_widget *widget; int widgetIndex; - // RCT2_CALLPROC_X(0x006EB15C, 0, 0, 0, 0, w, dpi, 0); - // return; - if ((w->flags & WF_TRANSPARENT) && !(w->flags & WF_5)) gfx_fill_rect(dpi, w->x, w->y, w->x + w->width - 1, w->y + w->height - 1, 0x2000000 | 51); @@ -1451,8 +1681,8 @@ void window_resize(rct_window *w, int dw, int dh) w->width = clamp(w->min_width, w->width + dw, w->max_width); w->height = clamp(w->min_height, w->height + dh, w->max_height); - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], w->width, w->height, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); + window_event_invalidate_call(w); // Update scroll widgets for (i = 0; i < 3; i++) { @@ -1534,9 +1764,8 @@ void tool_cancel() if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_TOOL_ACTIVE; - // - RCT2_CALLPROC_EBPSAFE(0x0068AAE1); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + map_invalidate_selection_rect(); + map_invalidate_map_selection_tiles(); // Reset map selection RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) = 0; @@ -1555,7 +1784,7 @@ void tool_cancel() RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) ); if (w != NULL) - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_ABORT], 0, 0, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0); + window_event_tool_abort_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16)); } } } @@ -1586,6 +1815,33 @@ void window_guest_list_init_vars_b() RCT2_GLOBAL(0x00F1AF20, uint16) = 0; } +static void window_event_call_address(int address, rct_window *w) +{ + #ifdef _MSC_VER + __asm { + push address + push w + mov esi, w + call[esp + 4] + add esp, 8 + } + #else + __asm__ ( "\ + push %[address]\n\ + mov eax, %[w] \n\ + push eax \n\ + mov esi, %[w] \n\ + call [esp+4] \n\ + add esp, 8 \n\ + " : [address] "+m" (address), [w] "+m" (w) : : "eax", "esi" ); + #endif +} + +void window_event_close_call(rct_window* w) +{ + window_event_call_address(w->event_handlers[WE_CLOSE], w); +} + void window_event_mouse_up_call(rct_window* w, int widgetIndex) { RCT2_CALLPROC_X(w->event_handlers[WE_MOUSE_UP], 0, 0, 0, widgetIndex, (int)w, (int)&(w->event_handlers[widgetIndex]), 0); @@ -1593,7 +1849,7 @@ void window_event_mouse_up_call(rct_window* w, int widgetIndex) void window_event_resize_call(rct_window* w) { - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_call_address(w->event_handlers[WE_RESIZE], w); } void window_event_mouse_down_call(rct_window *w, int widgetIndex) @@ -1634,11 +1890,138 @@ void window_event_mouse_down_call(rct_window *w, int widgetIndex) #endif } +void window_event_dropdown_call(rct_window* w, int widgetIndex, int dropdownIndex) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_DROPDOWN], dropdownIndex, 0, 0, widgetIndex, (int)w, 0, 0); +} + +void window_event_unknown_05_call(rct_window* w) +{ + window_event_call_address(w->event_handlers[WE_UNKNOWN_05], w); +} + +void window_event_update_call(rct_window *w) +{ + window_event_call_address(w->event_handlers[WE_UPDATE], w); +} + +void window_event_unknown_07_call(rct_window* w) +{ + window_event_call_address(w->event_handlers[WE_UNKNOWN_07], w); +} + +void window_event_unknown_08_call(rct_window* w) +{ + window_event_call_address(w->event_handlers[WE_UNKNOWN_08], w); +} + +void window_event_tool_update_call(rct_window* w, int widgetIndex, int x, int y) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UPDATE], x, y, 0, widgetIndex, (int)w, 0, 0); +} + +void window_event_tool_down_call(rct_window* w, int widgetIndex, int x, int y) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DOWN], x, y, 0, widgetIndex, (int)w, 0, 0); +} + +void window_event_tool_drag_call(rct_window* w, int widgetIndex, int x, int y) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DRAG], x, y, 0, widgetIndex, (int)w, 0, 0); +} + +void window_event_tool_up_call(rct_window* w, int widgetIndex, int x, int y) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UP], x, y, 0, widgetIndex, (int)w, 0, 0); +} + +void window_event_tool_abort_call(rct_window* w, int widgetIndex) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_ABORT], 0, 0, 0, widgetIndex, (int)w, 0, 0); +} + +void window_event_unknown_0E_call(rct_window* w) +{ + window_event_call_address(w->event_handlers[WE_UNKNOWN_0E], w); +} + +int window_get_scroll_size(rct_window *w, int scrollIndex, int *width, int *height) +{ + rct_widget *widget = window_get_scroll_widget(w, scrollIndex); + int widgetIndex = window_get_widget_index(w, widget); + + int eax = scrollIndex, ebx = scrollIndex * sizeof(rct_scroll), ecx = 0, edx = 0, esi = (int)w, edi = widgetIndex * sizeof(rct_widget), ebp = 0; + RCT2_CALLFUNC_X(w->event_handlers[WE_SCROLL_GETSIZE], & eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + *width = ecx; + *height = edx; + return 1; +} + +void window_event_scroll_mousedown_call(rct_window* w, int scrollIndex, int x, int y) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEDOWN], scrollIndex, 0, x, y, (int)w, (int)window_get_scroll_widget(w, scrollIndex), 0); +} + +void window_event_unknown_11_call(rct_window* w) +{ + window_event_call_address(w->event_handlers[WE_UNKNOWN_11], w); +} + +void window_event_scroll_mouseover_call(rct_window* w, int scrollIndex, int x, int y) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_MOUSEOVER], scrollIndex, 0, x, y, (int)w, (int)window_get_scroll_widget(w, scrollIndex), 0); +} + +void window_event_textinput_call(rct_window *w, int widgetIndex, char *text) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_TEXT_INPUT], 0, 0, text != NULL, widgetIndex, (int)w, (int)text, 0); +} + +void window_event_unknown_14_call(rct_window* w) +{ + window_event_call_address(w->event_handlers[WE_UNKNOWN_14], w); +} + +void window_event_unknown_15_call(rct_window* w, int scrollIndex, int scrollAreaType) +{ + rct_widget *widget = window_get_scroll_widget(w, scrollIndex); + RCT2_CALLPROC_X(w->event_handlers[WE_UNKNOWN_15], scrollIndex * sizeof(rct_scroll), 0, scrollAreaType, scrollIndex, (int)w, (int)widget, 0); +} + +rct_string_id window_event_tooltip_call(rct_window* w, int widgetIndex) +{ + int eax = widgetIndex, ebx, ecx, edx, esi = (int)w, edi, ebp; + RCT2_CALLFUNC_X(w->event_handlers[WE_TOOLTIP], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return eax & 0xFFFF; +} + +int window_event_cursor_call(rct_window* w, int widgetIndex, int x, int y) +{ + int eax = widgetIndex, ebx = -1, ecx = x, edx = y, esi = (int)w, edi = (int)&w->widgets[widgetIndex], ebp; + RCT2_CALLFUNC_X(w->event_handlers[WE_CURSOR], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return ebx; +} + +void window_event_moved_call(rct_window* w, int x, int y) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_MOVED], 0, 0, x, y, (int)w, 0, 0); +} + void window_event_invalidate_call(rct_window* w) { RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); } +void window_event_paint_call(rct_window* w, rct_drawpixelinfo *dpi) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_PAINT], 0, 0, 0, 0, (int)w, (int)dpi, 0); +} + +void window_event_scroll_paint_call(rct_window* w, rct_drawpixelinfo *dpi, int scrollIndex) +{ + RCT2_CALLPROC_X(w->event_handlers[WE_SCROLL_PAINT], scrollIndex, 0, 0, 0, (int)w, (int)dpi, 0); +} + /** * rct2: New function not from rct2 * Bubbles an item one position up in the window list. @@ -1650,13 +2033,45 @@ void window_bubble_list_item(rct_window* w, int item_position){ w->list_item_positions[item_position + 1] = swap; } +/* rct2: 0x006ED710 + * Called after a window resize to move windows if they + * are going to be out of sight. + */ +void window_relocate_windows(int width, int height){ + int new_location = 8; + for (rct_window* w = g_window_list; w < RCT2_NEW_WINDOW; w++){ + + // Work out if the window requires moving + if (w->x + 10 < width){ + if (w->flags&(WF_STICK_TO_BACK | WF_STICK_TO_FRONT)){ + if (w->y -22 < height)continue; + } + if (w->y + 10 < height)continue; + } + + // Calculate the new locations + int x = w->x; + int y = w->y; + w->x = new_location; + w->y = new_location + 28; + + // Move the next new location so windows are not directly on top + new_location += 8; + + // Adjust the viewport if required. + if (w->viewport){ + w->viewport->x -= x - w->x; + w->viewport->y -= y - w->y; + } + } +} /** * rct2: 0x0066B905 */ void window_resize_gui(int width, int height) { - if (RCT2_GLOBAL(0x9DEA68, uint8) & 0xE){ + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 0xE){ window_resize_gui_scenario_editor(width, height); return; } @@ -1709,6 +2124,11 @@ void window_resize_gui(int width, int height) exitWind->x = width - 40; exitWind->y = height - 64; } + + rct_window *optionsWind = window_find_by_class(WC_TITLE_OPTIONS); + if (optionsWind != NULL) { + optionsWind->x = width - 80; + } } /** @@ -1804,13 +2224,13 @@ void sub_6EA73F() { rct_window *w; - if (RCT2_GLOBAL(0x009DEA6E, uint8) != 0) + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) RCT2_GLOBAL(0x01423604, uint32)++; for (w = RCT2_LAST_WINDOW; w >= g_window_list; w--) { window_update_scroll_widgets(w); window_invalidate_pressed_image_buttons(w); - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); } } @@ -2012,4 +2432,96 @@ void window_move_and_snap(rct_window *w, int newWindowX, int newWindowY, int sna int window_can_resize(rct_window *w) { return (w->flags & WF_RESIZABLE) && (w->min_width != w->max_width || w->min_height != w->max_height); +} + +/** + * + * rct2: 0x006EE3C3 + */ +void textinput_cancel() +{ + rct_window *w; + + // Close the new text input window + window_close_by_class(WC_TEXTINPUT); + + // The following code is only necessary for the old Windows text input dialog. In theory this isn't used anymore, but can + // still be triggered via original code paths. + RCT2_CALLPROC_EBPSAFE(0x0040701D); + if (RCT2_GLOBAL(0x009DEB8C, uint8) != 255) { + RCT2_CALLPROC_EBPSAFE(0x006EE4E2); + w = window_find_by_number( + RCT2_GLOBAL(RCT2_ADDRESS_TEXTINPUT_WINDOWCLASS, rct_windowclass), + RCT2_GLOBAL(RCT2_ADDRESS_TEXTINPUT_WINDOWNUMBER, rct_windownumber) + ); + if (w != NULL) { + window_event_textinput_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TEXTINPUT_WIDGETINDEX, uint16), NULL); + } + } +} + +void window_start_textbox(rct_window *call_w, int call_widget, rct_string_id existing_text, uint32 existing_args, int maxLength) +{ + if (gUsingWidgetTextBox) + window_cancel_textbox(); + + gUsingWidgetTextBox = true; + gCurrentTextBox.window.classification = call_w->classification; + gCurrentTextBox.window.number = call_w->number; + gCurrentTextBox.widget_index = call_widget; + gTextBoxFrameNo = 0; + + gMaxTextBoxInputLength = maxLength; + + window_close_by_class(WC_TEXTINPUT); + + // Clear the text input buffer + memset(gTextBoxInput, 0, maxLength); + + // Enter in the the text input buffer any existing + // text. + if (existing_text != (rct_string_id)STR_NONE) + format_string(gTextBoxInput, existing_text, &existing_args); + + // In order to prevent strings that exceed the maxLength + // from crashing the game. + gTextBoxInput[maxLength - 1] = '\0'; + + platform_start_text_input(gTextBoxInput, maxLength); +} + +void window_cancel_textbox() +{ + if (gUsingWidgetTextBox) { + rct_window *w = window_find_by_number( + gCurrentTextBox.window.classification, + gCurrentTextBox.window.number + ); + gCurrentTextBox.window.classification = 255; + gCurrentTextBox.window.number = 0; + platform_stop_text_input(); + gUsingWidgetTextBox = false; + widget_invalidate(w, gCurrentTextBox.widget_index); + gCurrentTextBox.widget_index = WWT_LAST; + } +} + +void window_update_textbox_caret() +{ + gTextBoxFrameNo++; + if (gTextBoxFrameNo > 30) + gTextBoxFrameNo = 0; +} + +void window_update_textbox() +{ + if (gUsingWidgetTextBox) { + gTextBoxFrameNo = 0; + rct_window *w = window_find_by_number( + gCurrentTextBox.window.classification, + gCurrentTextBox.window.number + ); + widget_invalidate(w, gCurrentTextBox.widget_index); + window_event_textinput_call(w, gCurrentTextBox.widget_index, gTextBoxInput); + } } \ No newline at end of file diff --git a/src/interface/window.h b/src/interface/window.h index 06546998f9..6196f8fb67 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -30,6 +30,11 @@ struct rct_window; union rct_window_event; +extern uint8 TextInputDescriptionArgs[8]; +extern char gTextBoxInput[512]; +extern int gMaxTextBoxInputLength; +extern int gTextBoxFrameNo; +extern bool gUsingWidgetTextBox; typedef void wndproc(struct rct_window*, union rct_window_event*); @@ -46,6 +51,8 @@ typedef struct { int widget_index; } widget_identifier; +extern widget_identifier gCurrentTextBox; + /** * Widget structure * size: 0x10 @@ -190,7 +197,7 @@ typedef struct rct_window { uint64 enabled_widgets; // 0x008 uint64 disabled_widgets; // 0x010 uint64 pressed_widgets; // 0x018 - uint64 var_020; + uint64 hold_down_widgets; // 0x020 rct_widget* widgets; // 0x028 sint16 x; // 0x02C sint16 y; // 0x02E @@ -223,7 +230,7 @@ typedef struct rct_window { }; sint16 page; // 0x48A sint16 var_48C; - sint16 frame_no; // 0x48E updated every tic for motion in windows sprites + uint16 frame_no; // 0x48E updated every tic for motion in windows sprites uint16 list_information_type; // 0x490 0 for none, Used as current position of marquee in window_peep sint16 var_492; uint32 var_494; @@ -272,8 +279,8 @@ typedef enum { WE_UNKNOWN_14 = 20, WE_UNKNOWN_15 = 21, // scroll mouse move? WE_TOOLTIP = 22, - WE_UNKNOWN_17 = 23, // tooltip related - WE_UNKNOWN_18 = 24, + WE_CURSOR = 23, + WE_MOVED = 24, WE_INVALIDATE = 25, WE_PAINT = 26, WE_SCROLL_PAINT = 27, @@ -302,6 +309,8 @@ typedef enum { WF_10 = (1 << 10), WF_WHITE_BORDER_ONE = (1 << 12), WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13), + + WF_NO_SNAPPING = (1 << 15) } WINDOW_FLAGS; enum SCROLL_FLAGS { @@ -386,16 +395,31 @@ enum { WC_MAP_TOOLTIP = 41, WC_EDITOR_OBJECT_SELECTION = 42, WC_EDITOR_INVENTION_LIST = 43, + WC_EDITOR_INVENTION_LIST_DRAG = 44, WC_EDITOR_SCENARIO_OPTIONS = 45, WC_EDTIOR_OBJECTIVE_OPTIONS = 46, - WC_47, - WC_48, + WC_MANAGE_TRACK_DESIGN = 47, + WC_TRACK_DELETE_PROMPT = 48, + WC_INSTALL_TRACK = 49, WC_CLEAR_SCENERY = 50, - WC_MANAGE_TRACK_DESIGN = 89, WC_CHEATS = 110, WC_RESEARCH = 111, WC_VIEWPORT = 112, - WC_TEXTINPUT = 113 + WC_TEXTINPUT = 113, + WC_MAPGEN = 114, + WC_LOADSAVE = 115, + WC_LOADSAVE_OVERWRITE_PROMPT = 116, + WC_TITLE_OPTIONS = 117, + WC_LAND_RIGHTS = 118, + WC_THEMES = 119, + WC_TILE_INSPECTOR = 120, + WC_CHANGELOG = 121, + + // Only used for colour schemes + WC_STAFF = 220, + WC_EDITOR_TRACK_BOTTOM_TOOLBAR = 221, + WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR = 222, + } WINDOW_CLASS; enum PROMPT_MODE { @@ -405,6 +429,25 @@ enum PROMPT_MODE { PM_QUIT }; +typedef enum { + BTM_TB_DIRTY_FLAG_MONEY = (1 << 0), + BTM_TB_DIRTY_FLAG_DATE = (1 << 1), + BTM_TB_DIRTY_FLAG_PEEP_COUNT = (1 << 2), + BTM_TB_DIRTY_FLAG_CLIMATE = (1 << 3), + BTM_TB_DIRTY_FLAG_PARK_RATING = (1 << 4) +} BTM_TOOLBAR_DIRTY_FLAGS; + +enum { + LOADSAVETYPE_LOAD = 0 << 0, + LOADSAVETYPE_SAVE = 1 << 0, + + LOADSAVETYPE_GAME = 0 << 1, + LOADSAVETYPE_LANDSCAPE = 1 << 1, + LOADSAVETYPE_SCENARIO = 2 << 1, + LOADSAVETYPE_TRACK = 3 << 1, +}; + + // rct2: 0x01420078 extern rct_window* g_window_list; @@ -415,11 +458,13 @@ void window_dispatch_update_all(); void window_update_all(); rct_window *window_create(int x, int y, int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags); rct_window *window_create_auto_pos(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags); +rct_window *window_create_centred(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags); void window_close(rct_window *window); void window_close_by_class(rct_windowclass cls); void window_close_by_number(rct_windowclass cls, rct_windownumber number); void window_close_top(); void window_close_all(); +void window_close_all_except_class(rct_windowclass cls); rct_window *window_find_by_class(rct_windowclass cls); rct_window *window_find_by_number(rct_windowclass cls, rct_windownumber number); rct_window *window_find_from_point(int x, int y); @@ -427,13 +472,13 @@ int window_find_widget_from_point(rct_window *w, int x, int y); void window_invalidate(rct_window *window); void window_invalidate_by_class(rct_windowclass cls); void window_invalidate_by_number(rct_windowclass cls, rct_windownumber number); +void window_invalidate_all(); void widget_invalidate(rct_window *w, int widgetIndex); void widget_invalidate_by_class(rct_windowclass cls, int widgetIndex); void widget_invalidate_by_number(rct_windowclass cls, rct_windownumber number, int widgetIndex); void window_init_scroll_widgets(rct_window *w); void window_update_scroll_widgets(rct_window *w); int window_get_scroll_data_index(rct_window *w, int widget_index); -int window_get_scroll_size(rct_window *w, int scrollIndex, int *width, int *height); rct_window *window_bring_to_front(rct_window *w); rct_window *window_bring_to_front_by_class(rct_windowclass cls); @@ -447,6 +492,7 @@ rct_window *window_get_main(); void window_scroll_to_viewport(rct_window *w); void window_scroll_to_location(rct_window *w, int x, int y, int z); void window_rotate_camera(rct_window *w); +void window_zoom_set(rct_window *w, int zoomLevel); void window_zoom_in(rct_window *w); void window_zoom_out(rct_window *w); @@ -470,15 +516,17 @@ void window_update_viewport_ride_music(); // Open window functions void window_main_open(); +void window_relocate_windows(int width, int height); void window_resize_gui(int width, int height); void window_resize_gui_scenario_editor(int width, int height); -void window_game_top_toolbar_open(); +void window_top_toolbar_open(); void window_game_bottom_toolbar_open(); void window_about_open(); void window_footpath_open(); void window_save_prompt_open(); void window_title_menu_open(); void window_title_exit_open(); +void window_title_options_open(); void window_title_logo_open(); void window_news_open(); void window_scenarioselect_open(); @@ -486,8 +534,10 @@ void window_track_list_open(ride_list_item item); void window_clear_scenery_open(); void window_land_open(); void window_water_open(); +void window_land_rights_open(); void window_staff_list_open(); void window_guest_list_open(); +void window_guest_list_open_with_filter(int type, int index); void window_map_open(); void window_options_open(); void window_shortcut_keys_open(); @@ -512,7 +562,9 @@ void window_ride_construct(rct_window *w); void window_ride_list_open(); rct_window * window_construction_open(); void window_track_place_open(); -void window_new_ride_open(); +rct_window *window_new_ride_open(); +rct_window *window_new_ride_open_research(); +void window_install_track_open(const char* path); void window_banner_open(rct_windownumber number); void window_sign_open(rct_windownumber number); void window_sign_small_open(rct_windownumber number); @@ -523,10 +575,15 @@ void window_music_credits_open(); void window_publisher_credits_open(); void window_track_manage_open(); void window_viewport_open(); -void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, rct_string_id existing_text, uint32 existing_args); +void window_themes_open(); +void window_tile_inspector_open(); +void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, rct_string_id existing_text, uint32 existing_args, int maxLength); +void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, utf8string existing_text, int maxLength); +rct_window *window_mapgen_open(); +rct_window *window_loadsave_open(int type, char *defaultName); +rct_window *window_changelog_open(); void window_editor_main_open(); -void window_editor_top_toolbar_open(); void window_editor_bottom_toolbar_open(); void window_editor_object_selection_open(); void window_editor_inventions_list_open(); @@ -546,16 +603,49 @@ void window_map_tooltip_update_visibility(); void window_staff_list_init_vars(); +void window_event_close_call(rct_window* w); void window_event_mouse_up_call(rct_window* w, int widgetIndex); void window_event_resize_call(rct_window* w); -void window_event_mouse_down_call(rct_window* w, int widgetIndex); +void window_event_mouse_down_call(rct_window *w, int widgetIndex); +void window_event_dropdown_call(rct_window* w, int widgetIndex, int dropdownIndex); +void window_event_unknown_05_call(rct_window* w); +void window_event_update_call(rct_window *w); +void window_event_unknown_07_call(rct_window* w); +void window_event_unknown_08_call(rct_window* w); +void window_event_tool_update_call(rct_window* w, int widgetIndex, int x, int y); +void window_event_tool_down_call(rct_window* w, int widgetIndex, int x, int y); +void window_event_tool_drag_call(rct_window* w, int widgetIndex, int x, int y); +void window_event_tool_up_call(rct_window* w, int widgetIndex, int x, int y); +void window_event_tool_abort_call(rct_window* w, int widgetIndex); +void window_event_unknown_0E_call(rct_window* w); +int window_get_scroll_size(rct_window *w, int scrollIndex, int *width, int *height); +void window_event_scroll_mousedown_call(rct_window* w, int scrollIndex, int x, int y); +void window_event_unknown_11_call(rct_window* w); +void window_event_scroll_mouseover_call(rct_window* w, int scrollIndex, int x, int y); +void window_event_textinput_call(rct_window *w, int widgetIndex, char *text); +void window_event_unknown_14_call(rct_window* w); +void window_event_unknown_15_call(rct_window* w, int scrollIndex, int scrollAreaType); +rct_string_id window_event_tooltip_call(rct_window* w, int widgetIndex); +int window_event_cursor_call(rct_window* w, int widgetIndex, int x, int y); +void window_event_moved_call(rct_window* w, int x, int y); void window_event_invalidate_call(rct_window* w); +void window_event_paint_call(rct_window* w, rct_drawpixelinfo *dpi); +void window_event_scroll_paint_call(rct_window* w, rct_drawpixelinfo *dpi, int scrollIndex); void sub_6EA73F(); +void textinput_cancel(); void window_move_and_snap(rct_window *w, int newWindowX, int newWindowY, int snapProximity); int window_can_resize(rct_window *w); +void window_start_textbox(rct_window *call_w, int call_widget, rct_string_id existing_text, uint32 existing_args, int maxLength); +void window_cancel_textbox(); +void window_update_textbox_caret(); +void window_update_textbox(); + +//Cheat: in-game land ownership editor +void toggle_ingame_land_ownership_editor(); + #ifdef _MSC_VER #define window_get_register(w) \ __asm mov w, esi @@ -569,13 +659,18 @@ int window_can_resize(rct_window *w); __asm mov widgetIndex, dx \ __asm mov w, esi - #define window_text_input_get_registers(w, widgetIndex, result, text) \ + #define window_text_input_get_registers(w, widgetIndex, result, text) \ __asm mov widgetIndex, dx \ - __asm mov result, cl \ + __asm mov result, cl \ __asm mov w, esi \ __asm mov text, edi - #define window_scrollmouse_get_registers(w, x, y) \ + #define window_scroll_get_registers(w, i) \ + __asm mov i, ax \ + __asm mov w, esi + + #define window_scrollmouse_get_registers(w, i, x, y) \ + __asm mov i, ax \ __asm mov x, cx \ __asm mov y, dx \ __asm mov w, esi @@ -595,6 +690,32 @@ int window_can_resize(rct_window *w); #define window_paint_get_registers(w, dpi) \ __asm mov w, esi \ __asm mov dpi, edi + + #define window_scrollpaint_get_registers(w, dpi, i) \ + __asm mov i, ax \ + __asm mov w, esi \ + __asm mov dpi, edi + + #define window_scrollsize_set_registers(width, height) \ + __asm mov ecx, width \ + __asm mov edx, height + + #define window_cursor_get_registers(w, widgetIndex, x, y) \ + __asm mov widgetIndex, ax \ + __asm mov x, cx \ + __asm mov y, dx \ + __asm mov w, esi + + #define window_cursor_set_registers(cursorId) \ + __asm mov ebx, cursorId + + #define window_tooltip_get_registers(w, widgetIndex) \ + __asm mov widgetIndex, ax \ + __asm mov w, esi + + #define window_tooltip_set_registers(value) \ + __asm mov ax, value + #else #define window_get_register(w) \ __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); @@ -605,24 +726,29 @@ int window_can_resize(rct_window *w); #define window_dropdown_get_registers(w, widgetIndex, dropdownIndex) \ __asm__ ( "mov %["#dropdownIndex"], ax " : [dropdownIndex] "+m" (dropdownIndex) ); \ - __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ + __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); - #define window_text_input_get_registers(w, widgetIndex, result, text) \ - __asm__ ( "mov %[_cl], cl " : [_cl] "+m" (result) ); \ + #define window_text_input_get_registers(w, widgetIndex, result, text) \ + __asm__ ( "mov %[_cl], cl " : [_cl] "+m" (result) ); \ __asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) ); \ __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); \ __asm__ ( "mov %[text], edi " : [text] "+m" (text) ); - #define window_scrollmouse_get_registers(w, x, y) \ - __asm__ ( "mov %["#x"], cx " : [x] "+m" (x) ); \ - __asm__ ( "mov %["#y"], dx " : [y] "+m" (y) ); \ + #define window_scroll_get_registers(w, i) \ + __asm__ ( "mov %["#i"], ax " : [i] "+m" (i) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); + + #define window_scrollmouse_get_registers(w, i, x, y) \ + __asm__ ( "mov %["#i"], ax " : [i] "+m" (i) ); \ + __asm__ ( "mov %["#x"], cx " : [x] "+m" (x) ); \ + __asm__ ( "mov %["#y"], dx " : [y] "+m" (y) ); \ __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); #define window_tool_get_registers(w, widgetIndex, x, y) \ - __asm__ ( "mov %["#x"], ax " : [x] "+m" (x) ); \ - __asm__ ( "mov %["#y"], bx " : [y] "+m" (y) ); \ - __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ + __asm__ ( "mov %["#x"], ax " : [x] "+m" (x) ); \ + __asm__ ( "mov %["#y"], bx " : [y] "+m" (y) ); \ + __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); #define window_textinput_get_registers(w, widgetIndex, result, text) \ @@ -634,6 +760,31 @@ int window_can_resize(rct_window *w); #define window_paint_get_registers(w, dpi) \ __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); \ __asm__ ( "mov %["#dpi"], edi " : [dpi] "+m" (dpi) ); + + #define window_scrollpaint_get_registers(w, dpi, i) \ + __asm__ ( "mov %["#i"], ax " : [i] "+m" (i) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); \ + __asm__ ( "mov %["#dpi"], edi " : [dpi] "+m" (dpi) ); + + #define window_scrollsize_set_registers(width, height) \ + __asm__ ( "mov ecx, %[width] " : [width] "+m" (width) ); \ + __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); + + #define window_cursor_get_registers(w, widgetIndex, x, y) \ + __asm__ ( "mov %["#widgetIndex"], ax " : [widgetIndex] "+m" (widgetIndex) ); \ + __asm__ ( "mov %["#x"], cx " : [x] "+m" (x) ); \ + __asm__ ( "mov %["#y"], dx " : [y] "+m" (y) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); + + #define window_cursor_set_registers(cursorId) \ + __asm__ ( "mov ebx, %[cursorId] " : [cursorId] "+m" (cursorId) ); + + #define window_tooltip_get_registers(w, widgetIndex) \ + __asm__ ( "mov %["#widgetIndex"], ax " : [widgetIndex] "+m" (widgetIndex) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); + + #define window_tooltip_set_registers(value) \ + __asm__ ( "mov ax, %["#value"] " : [value] "+m" (value) ); #endif #endif diff --git a/src/intro.c b/src/intro.c index 17f22c2ce0..e5d9e09bef 100644 --- a/src/intro.c +++ b/src/intro.c @@ -23,7 +23,7 @@ #include "drawing/drawing.h" #include "intro.h" #include "localisation/localisation.h" -#include "platform/osinterface.h" +#include "platform/platform.h" #include "sprites.h" static void screen_intro_process_mouse_input(); @@ -262,7 +262,7 @@ void intro_update() (*part) = 0; // Change palette - RCT2_CALLPROC_EBPSAFE(0x006837E3); + load_palette(); RCT2_GLOBAL(0x009E2C78, sint32) = 0; gfx_invalidate_screen(); diff --git a/src/localisation/currency.h b/src/localisation/currency.h index 2b60f996f4..69b40556aa 100644 --- a/src/localisation/currency.h +++ b/src/localisation/currency.h @@ -47,7 +47,7 @@ typedef struct { // Rate is relative to 0.1 GBP int rate; char symbol[8]; - char affix; + int affix; } rct_currency_spec; // List of currency formats diff --git a/src/localisation/language.c b/src/localisation/language.c index 3168bf185f..5d4e1b17d1 100644 --- a/src/localisation/language.c +++ b/src/localisation/language.c @@ -19,7 +19,18 @@ *****************************************************************************/ #include "../addresses.h" +#include "../object.h" +#include "../util/util.h" #include "localisation.h" +#include "../openrct2.h" + +typedef struct { + int id; + int num_strings; + char **strings; + size_t string_data_size; + char *string_data; +} language_data; const char *language_names[LANGUAGE_COUNT] = { "", // LANGUAGE_UNDEFINED @@ -31,7 +42,8 @@ const char *language_names[LANGUAGE_COUNT] = { "Magyar", // LANGUAGE_HUNGARIAN "Polski", // LANGUAGE_POLISH "Espa\u00F1ol", // LANGUAGE_SPANISH - "Svenska" // LANGUAGE_SWEDISH + "Svenska", // LANGUAGE_SWEDISH + "Italiano" // LANGUAGE_ITALIAN }; const char *language_filenames[LANGUAGE_COUNT] = { @@ -44,20 +56,19 @@ const char *language_filenames[LANGUAGE_COUNT] = { "hungarian", // LANGUAGE_HUNGARIAN "polish", // LANGUAGE_POLISH "spanish_sp", // LANGUAGE_SPANISH - "swedish" // LANGUAGE_SWEDISH + "swedish", // LANGUAGE_SWEDISH + "italian" // LANGUAGE_ITALIAN }; int gCurrentLanguage = LANGUAGE_UNDEFINED; -// Buffer storing all the string data -long language_buffer_size = 0; -char *language_buffer = NULL; +language_data _languageFallback = { 0 }; +language_data _languageCurrent = { 0 }; -// List of string pointers into the string data -int language_num_strings = 0; -char **language_strings = NULL; +const char **_languageOriginal = (char**)0x009BF2D4; -static int language_open_file(const char *filename); +static int language_open_file(const char *filename, language_data *language); +static void language_close(language_data *language); static int utf8_get_next(char *char_ptr, char **nextchar_ptr) { @@ -70,6 +81,8 @@ static int utf8_get_next(char *char_ptr, char **nextchar_ptr) } else if (!(char_ptr[0] & 0x20)) { result = ((char_ptr[0] & 0x1F) << 6) | (char_ptr[1] & 0x3F); numBytes = 2; + } else { + numBytes = 1; } if (nextchar_ptr != NULL) @@ -79,22 +92,44 @@ static int utf8_get_next(char *char_ptr, char **nextchar_ptr) const char *language_get_string(rct_string_id id) { - const char *rct = RCT2_ADDRESS(0x009BF2D4, const char*)[id]; - const char *openrct = language_strings == NULL ? NULL : language_strings[id]; - const char *str = (openrct == NULL || strlen(openrct) == 0 ? rct : openrct); - return str == NULL ? "" : str; + const char *openrctString = NULL; + + if (id == (rct_string_id)STR_NONE) + return NULL; + + if (_languageCurrent.num_strings > id) + openrctString = _languageCurrent.strings[id]; + else if (_languageFallback.num_strings > id) + openrctString = _languageFallback.strings[id]; + + if (id >= STR_OPENRCT2_BEGIN_STRING_ID) { + return openrctString != NULL ? openrctString : "(undefined string)"; + } else { + const char *rct = _languageOriginal[id]; + const char *str = (openrctString == NULL || strlen(openrctString) == 0 ? rct : openrctString); + return str == NULL ? "" : str; + } } int language_open(int id) { - char filename[_MAX_PATH]; + static const char *languagePath = "%s/data/language/%s.txt"; + char filename[MAX_PATH]; - language_close(); + language_close_all(); if (id == LANGUAGE_UNDEFINED) return 1; - sprintf(filename, "data/language/%s.txt", language_filenames[id]); - if (language_open_file(filename)) { + if (id != LANGUAGE_ENGLISH_UK) { + sprintf(filename, languagePath, gExePath, language_filenames[LANGUAGE_ENGLISH_UK]); + if (language_open_file(filename, &_languageFallback)) { + _languageFallback.id = LANGUAGE_ENGLISH_UK; + } + } + + sprintf(filename, languagePath, gExePath, language_filenames[id]); + if (language_open_file(filename, &_languageCurrent)) { + _languageCurrent.id = id; gCurrentLanguage = id; return 1; } @@ -102,6 +137,15 @@ int language_open(int id) return 0; } +void language_close_all() +{ + language_close(&_languageFallback); + language_close(&_languageCurrent); + _languageFallback.id = LANGUAGE_UNDEFINED; + _languageCurrent.id = LANGUAGE_UNDEFINED; + gCurrentLanguage = LANGUAGE_UNDEFINED; +} + /** * Partial support to open a uncompiled language file which parses tokens and converts them to the corresponding character * code. Due to resource strings (strings in scenarios and objects) being written to the original game's string table, @@ -118,27 +162,36 @@ int language_open(int id) * colon and before the new line will be saved as the string. Tokens are written with inside curly braces {TOKEN}. * Use # at the beginning of a line to leave a comment. */ -static int language_open_file(const char *filename) +static int language_open_file(const char *filename, language_data *language) { + assert(filename != NULL); + assert(language != NULL); + FILE *f = fopen(filename, "rb"); if (f == NULL) return 0; fseek(f, 0, SEEK_END); - language_buffer_size = ftell(f); - language_buffer = calloc(1, language_buffer_size); + language->string_data_size = ftell(f) + 1; + language->string_data = calloc(1, language->string_data_size); fseek(f, 0, SEEK_SET); - fread(language_buffer, language_buffer_size, 1, f); + fread(language->string_data, language->string_data_size, 1, f); fclose(f); - language_strings = calloc(STR_COUNT, sizeof(char*)); + language->strings = calloc(STR_COUNT, sizeof(char*)); char *dst = NULL; char *token = NULL; char tokenBuffer[64]; - int i, stringIndex = 0, mode = 0, string_no; - for (i = 0; i < language_buffer_size; i++) { - char *src = &language_buffer[i]; + int stringIndex = 0, mode = 0, stringId, maxStringId = 0; + size_t i = 0; + + // Skim UTF-8 byte order mark + if (utf8_is_bom(language->string_data)) + i += 3; + + for (; i < language->string_data_size; i++) { + char *src = &language->string_data[i]; // Handle UTF-8 char *srcNext; @@ -154,16 +207,18 @@ static int language_open_file(const char *filename) // Search for a comment if (utf8Char == '#') { mode = 3; - } else if (utf8Char == ':' && string_no != -1) { + } else if (utf8Char == ':' && stringId != -1) { // Search for colon dst = src + 1; - language_strings[string_no] = dst; + language->strings[stringId] = dst; stringIndex++; mode = 1; } else if (!strncmp(src, "STR_", 4)){ // Copy in the string number, 4 characters only - if (sscanf(src, "STR_%4d", &string_no) != 1) { - string_no = -1; + if (sscanf(src, "STR_%4d", &stringId) != 1) { + stringId = -1; + } else { + maxStringId = max(maxStringId, stringId); } } break; @@ -198,22 +253,97 @@ static int language_open_file(const char *filename) } } } - language_num_strings = stringIndex; + language->num_strings = maxStringId + 1; + language->strings = realloc(language->strings, language->num_strings * sizeof(char*)); return 1; } -void language_close() +static void language_close(language_data *language) { - if (language_buffer != NULL) - free(language_buffer); - language_buffer = NULL; - language_buffer_size = 0; - - if (language_strings != NULL) - free(language_strings); - language_strings = NULL; - language_num_strings = 0; - - gCurrentLanguage = LANGUAGE_UNDEFINED; + SafeFree(language->strings); + SafeFree(language->string_data); + language->num_strings = 0; + language->string_data_size = 0; +} + +const int OpenRCT2LangIdToObjectLangId[] = { + 0, 0, 1, 3, 6, 2, 0, 0, 4, 7, 5 +}; + +/* rct2: 0x0098DA16 */ +uint16 ObjectTypeStringTableCount[] = { 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 }; + +/* rct2: 0x006A9E24*/ +rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/) +{ + char* pString = NULL; + int result = 0; + while (true) + { + uint8_t language_code = *(*pStringTable)++; + + if (language_code == 0xFF) //end of string table + break; + + // This is the ideal situation. Language found + if (language_code == OpenRCT2LangIdToObjectLangId[gCurrentLanguage])//1) + { + pString = *pStringTable; + result |= 1; + } + + // Just in case always load english into pString + if (language_code == 0 && !(result & 1)) + { + pString = *pStringTable; + result |= 2; + } + + // Failing that fall back to whatever is first string + if (!(result & 7)) + { + pString = *pStringTable; + result |= 4; + } + + // Skip over the actual string entry to get to the next + // entry + while (*(*pStringTable)++ != 0); + } + + // If not scenario text + if (RCT2_GLOBAL(0x9ADAFC, uint8_t) == 0) + { + int stringid = 3463; + for (int i = 0; i < type; i++) + { + int nrobjects = object_entry_group_counts[i]; + int nrstringtables = ObjectTypeStringTableCount[i]; + stringid += nrobjects * nrstringtables; + } + stringid += index * ObjectTypeStringTableCount[type]; + // Used by the object list to allocate name in plugin.dat + RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32) = stringid; + stringid += tableindex; + + //put pointer in stringtable + if (_languageCurrent.num_strings > stringid) + _languageCurrent.strings[stringid] = pString; + // Until all string related functions are finished copy + // to old array as well. + _languageOriginal[stringid] = pString; + return stringid; + } + else + { + int stringid = 3447 + tableindex; + //put pointer in stringtable + if (_languageCurrent.num_strings > stringid) + _languageCurrent.strings[stringid] = pString; + // Until all string related functions are finished copy + // to old array as well. + _languageOriginal[stringid] = pString; + return stringid; + } } diff --git a/src/localisation/language.h b/src/localisation/language.h index d7973d071f..c86906f773 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -34,6 +34,7 @@ enum { LANGUAGE_POLISH, LANGUAGE_SPANISH, LANGUAGE_SWEDISH, + LANGUAGE_ITALIAN, LANGUAGE_COUNT }; @@ -42,6 +43,8 @@ extern int gCurrentLanguage; const char *language_get_string(rct_string_id id); int language_open(int id); -void language_close(); +void language_close_all(); + +rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/); #endif diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c index d659e2ce0d..01cb13e66c 100644 --- a/src/localisation/localisation.c +++ b/src/localisation/localisation.c @@ -18,6 +18,7 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "../addresses.h" #include "../config.h" #include "../game.h" @@ -175,6 +176,8 @@ void format_comma_separated_integer(char **dest, long long value) char *dst = *dest; char *finish; char tmp; + const char *commaMark = language_get_string(5151); + const char *ch; // Negative sign if (value < 0) { @@ -193,7 +196,11 @@ void format_comma_separated_integer(char **dest, long long value) // Append group seperator if (groupIndex == 3) { groupIndex = 0; - *dst++ = ','; + + ch = commaMark; + while (*ch != 0) { + *dst++ = *ch++; + } } digit = value % 10; @@ -223,6 +230,9 @@ void format_comma_separated_fixed_2dp(char **dest, long long value) char *dst = *dest; char *finish; char tmp; + const char *commaMark = language_get_string(5151); + const char *decimalMark = language_get_string(5152); + const char *ch; // Negative sign if (value < 0) { @@ -239,7 +249,11 @@ void format_comma_separated_fixed_2dp(char **dest, long long value) digit = value % 10; value /= 10; *dst++ = '0' + digit; - *dst++ = '.'; + + ch = decimalMark; + while (*ch != 0) { + *dst++ = *ch++; + } if (value == 0) { *dst++ = '0'; @@ -250,7 +264,11 @@ void format_comma_separated_fixed_2dp(char **dest, long long value) // Append group seperator if (groupIndex == 3) { groupIndex = 0; - *dst++ = ','; + + ch = commaMark; + while (*ch != 0) { + *dst++ = *ch++; + } } digit = value % 10; @@ -276,16 +294,22 @@ void format_comma_separated_fixed_2dp(char **dest, long long value) void format_currency(char **dest, long long value) { - const rct_currency_spec *currencySpec = &g_currency_specs[gGeneral_config.currency_format]; + const rct_currency_spec *currencySpec = &g_currency_specs[gConfigGeneral.currency_format]; int rate = currencySpec->rate; value *= rate; // Negative sign if (value < 0) { + // Round the value away from zero + value = (value - 99) / 100; *(*dest)++ = '-'; value = -value; } + else{ + //Round the value away from zero + value = (value + 99) / 100; + } // Currency symbol const char *symbol = currencySpec->symbol; @@ -296,8 +320,7 @@ void format_currency(char **dest, long long value) *dest += strlen(*dest); } - // Divide by 100 to get rid of the pennies - format_comma_separated_integer(dest, value / 100); + format_comma_separated_integer(dest, value); // Currency symbol suffix if (currencySpec->affix == CURRENCY_SUFFIX) { @@ -308,7 +331,7 @@ void format_currency(char **dest, long long value) void format_currency_2dp(char **dest, long long value) { - const rct_currency_spec *currencySpec = &g_currency_specs[gGeneral_config.currency_format]; + const rct_currency_spec *currencySpec = &g_currency_specs[gConfigGeneral.currency_format]; int rate = currencySpec->rate; value *= rate; @@ -342,6 +365,88 @@ void format_currency_2dp(char **dest, long long value) } } +void format_date(char **dest, uint16 value) +{ + uint16 args[] = { date_get_month(value), date_get_year(value) + 1 }; + uint16 *argsRef = args; + format_string_part(dest, 2736, (char**)&argsRef); + (*dest)--; +} + +void format_length(char **dest, sint16 value) +{ + rct_string_id stringId = 2733; + + if (gConfigGeneral.measurement_format == MEASUREMENT_FORMAT_IMPERIAL) { + value = metres_to_feet(value); + stringId--; + } + + uint16 *argRef = &value; + format_string_part(dest, stringId, (char**)&argRef); + (*dest)--; +} + +void format_velocity(char **dest, uint16 value) +{ + rct_string_id stringId = 2734; + + if (gConfigGeneral.measurement_format == MEASUREMENT_FORMAT_METRIC) { + value = mph_to_kmph(value); + stringId++; + } + + uint16 *argRef = &value; + format_string_part(dest, stringId, (char**)&argRef); + (*dest)--; +} + +void format_duration(char **dest, uint16 value) +{ + uint16 minutes = value / 60; + uint16 seconds = value % 60; + uint16 args[] = { minutes, seconds }; + uint16 *argsRef = &args[1]; + rct_string_id stringId = 2720; + + if (minutes > 0) { + stringId += 2; + if (minutes != 1) + stringId += 2; + + argsRef--; + } + + if (seconds != 1) + stringId++; + + format_string_part(dest, stringId, (char**)&argsRef); + (*dest)--; +} + +void format_realtime(char **dest, uint16 value) +{ + uint16 hours = value / 60; + uint16 minutes = value % 60; + uint16 args[] = { hours, minutes }; + uint16 *argsRef = &args[1]; + rct_string_id stringId = 2726; + + if (hours > 0) { + stringId += 2; + if (hours != 1) + stringId += 2; + + argsRef--; + } + + if (minutes != 1) + stringId++; + + format_string_part(dest, stringId, (char**)&argsRef); + (*dest)--; +} + void format_string_code(unsigned char format_code, char **dest, char **args) { int value; @@ -418,13 +523,7 @@ void format_string_code(unsigned char format_code, char **dest, char **args) value = *((uint16*)*args); *args += 2; - uint16 dateArgs[] = { date_get_month(value), date_get_year(value) + 1 }; - uint16 *dateArgs2 = dateArgs; - char formatString[] = "?, Year ?"; - formatString[0] = FORMAT_MONTH; - formatString[8] = FORMAT_COMMA16; - format_string_part_from_raw(dest, formatString, (char**)&dateArgs2); - (*dest)--; + format_date(dest, value); break; case FORMAT_MONTH: // Pop argument @@ -439,15 +538,7 @@ void format_string_code(unsigned char format_code, char **dest, char **args) value = *((sint16*)*args); *args += 2; - if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8)) { - format_comma_separated_integer(dest, mph_to_kmph(value)); - strcpy(*dest, "kmh"); - *dest += strlen(*dest); - } else { - format_comma_separated_integer(dest, value); - strcpy(*dest, "mph"); - *dest += strlen(*dest); - } + format_velocity(dest, value); break; case FORMAT_POP16: *args += 2; @@ -460,45 +551,21 @@ void format_string_code(unsigned char format_code, char **dest, char **args) value = *((uint16*)*args); *args += 2; - if (value / 60 > 0) { - format_integer(dest, value / 60); - strcpy(*dest, value / 60 == 1 ? "min:" : "mins:"); - *dest += strlen(*dest); - } - - format_integer(dest, value % 60); - strcpy(*dest, value % 60 == 1 ? "sec" : "secs"); - *dest += strlen(*dest); + format_duration(dest, value); break; case FORMAT_REALTIME: // Pop argument value = *((uint16*)*args); *args += 2; - if (value / 60 > 0) { - format_integer(dest, value / 60); - strcpy(*dest, value / 60 == 1 ? "hour:" : "hours:"); - *dest += strlen(*dest); - } - - format_integer(dest, value % 60); - strcpy(*dest, value % 60 == 1 ? "min" : "mins"); - *dest += strlen(*dest); + format_realtime(dest, value); break; case FORMAT_LENGTH: // Pop argument value = *((sint16*)*args); *args += 2; - if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8)) { - format_comma_separated_integer(dest, value); - strcpy(*dest, "m"); - *dest += strlen(*dest); - } else { - format_comma_separated_integer(dest, metres_to_feet(value)); - strcpy(*dest, "ft"); - *dest += strlen(*dest); - } + format_length(dest, value); break; case FORMAT_SPRITE: // Pop argument @@ -549,7 +616,9 @@ void format_string_part_from_raw(char **dest, const char *src, char **args) void format_string_part(char **dest, rct_string_id format, char **args) { - if (format < 0x8000) { + if (format == (rct_string_id)STR_NONE) { + **dest = 0; + } else if (format < 0x8000) { // Language string format_string_part_from_raw(dest, language_get_string(format), args); } else if (format < 0x9000) { @@ -587,17 +656,20 @@ void format_string_part(char **dest, rct_string_id format, char **args) */ void format_string(char *dest, rct_string_id format, void *args) { - // RCT2_CALLPROC_X(0x006C2555, format, 0, (int)args, 0, 0, (int)dest, 0); format_string_part(&dest, format, (char**)&args); } +void format_string_raw(char *dest, char *src, void *args) +{ + format_string_part_from_raw(&dest, src, (char**)&args); +} + /** * rct2: 0x006E37F7 * error (eax) * format (bx) */ void error_string_quit(int error, rct_string_id format){ - //RCT2_CALLPROC_X(0x006E37F7, error, format, 0, 0, 0, 0, 0); RCT2_GLOBAL(0x14241A0, uint32) = error; RCT2_GLOBAL(0x9E2DA0, uint32) = 1; @@ -700,4 +772,13 @@ int get_string_length(char* buffer) } } return length; +} + +int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength) +{ + utf16 intermediateBuffer[512]; + + // TODO this supports only a maximum of 512 characters + MultiByteToWideChar(CP_ACP, 0, src, -1, intermediateBuffer, 512); + return WideCharToMultiByte(CP_UTF8, 0, intermediateBuffer, -1, dst, maxBufferLength, NULL, NULL); } \ No newline at end of file diff --git a/src/localisation/localisation.h b/src/localisation/localisation.h index 97068d7eed..c7bee7a75c 100644 --- a/src/localisation/localisation.h +++ b/src/localisation/localisation.h @@ -27,12 +27,17 @@ #include "string_ids.h" void format_string(char *dest, rct_string_id format, void *args); +void format_string_raw(char *dest, char *src, void *args); void generate_string_file(); void error_string_quit(int error, rct_string_id format); int get_string_length(char* buffer); void user_string_clear_all(); +rct_string_id user_string_allocate(int base, const char *text); void user_string_free(rct_string_id id); +bool is_user_string_id(rct_string_id stringId); + +int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength); #define MAX_USER_STRINGS 1024 #define USER_STRING_MAX_LENGTH 32 diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index 3e79f8f740..b1170543fe 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -71,6 +71,8 @@ enum { STR_MONTH_SHORT_DEC = STR_MONTH_SHORT_JAN + 11, STR_CLOSE_X = 824, + STR_CHOSEN_NAME_IN_USE_ALREADY = 825, + STR_TOO_MANY_NAMES_DEFINED = 826, STR_CLOSE_WINDOW_TIP = 828, STR_WINDOW_TITLE_TIP = 829, @@ -100,11 +102,19 @@ enum { STR_CREDIT_SPARE_6 = 863, STR_CREDIT_SPARE_7 = 864, + STR_DROPDOWN_GLYPH = 876, + STR_TOO_LOW = 877, + STR_TOO_HIGH = 878, + STR_CANT_LOWER_LAND_HERE = 879, + STR_CANT_RAISE_LAND_HERE = 880, + STR_LOAD_GAME = 882, STR_SAVE_GAME = 883, STR_LOAD_LANDSCAPE = 884, STR_SAVE_LANDSCAPE = 885, STR_QUIT_GAME = 886, + STR_QUIT_TO_MENU = 5158, + STR_EXIT_OPENRCT2 = 5159, STR_QUIT_SCENARIO_EDITOR = 887, STR_QUIT_ROLLERCOASTER_DESIGNER = 888, STR_QUIT_TRACK_DESIGNS_MANAGER = 889, @@ -112,6 +122,7 @@ enum { STR_SCREENSHOT = 891, STR_SCREENSHOT_SAVED_AS = 892, STR_SCREENSHOT_FAILED = 893, + STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND = 895, STR_VIEW_OPTIONS_TIP = 937, STR_ADJUST_LAND_TIP = 938, @@ -163,6 +174,10 @@ enum { STR_OVERALL_VIEW = 996, STR_VIEW_SELECTION = 997, + STR_REQUIRES_A_STATION_PLATFORM = 999, + STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT = 1000, + STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN = 1001, + STR_CANT_OPEN = 1002, STR_CANT_TEST = 1003, STR_CANT_CLOSE = 1004, @@ -180,6 +195,9 @@ enum { STR_CANT_CHANGE_OPERATING_MODE = 1017, STR_LOCATE_SUBJECT_TIP = 1027, + STR_OFF_EDGE_OF_MAP = 1028, + + STR_CAN_ONLY_BUILD_THIS_ON_LAND = 1034, STR_LOAD_GAME_DIALOG_TITLE = 1036, STR_LOAD_LANDSCAPE_DIALOG_TITLE = 1037, @@ -209,7 +227,7 @@ enum { STR_RIDE_MODE_NORMAL = STR_RIDE_MODE_START + 0, STR_RIDE_MODE_CONTINUOUS_CIRCUIT = STR_RIDE_MODE_START + 1, STR_RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE = STR_RIDE_MODE_START + 2, - STR_RIDE_MODE_POWERED_LAUNCH = STR_RIDE_MODE_START + 3, + STR_RIDE_MODE_POWERED_LAUNCH_PASSTROUGH = STR_RIDE_MODE_START + 3, STR_RIDE_MODE_SHUTTLE = STR_RIDE_MODE_START + 4, STR_RIDE_MODE_BOAT_HIRE = STR_RIDE_MODE_START + 5, STR_RIDE_MODE_UPWARD_LAUNCH = STR_RIDE_MODE_START + 6, @@ -241,7 +259,7 @@ enum { STR_RIDE_MODE_CROOKED_HOUSE = STR_RIDE_MODE_START + 32, STR_RIDE_MODE_FREEFALL_DROP = STR_RIDE_MODE_START + 33, STR_RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED = STR_RIDE_MODE_START + 34, - STR_RIDE_MODE_POWERED_LAUNCH_35 = STR_RIDE_MODE_START + 35, + STR_RIDE_MODE_POWERED_LAUNCH = STR_RIDE_MODE_START + 35, STR_RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED_MODE = STR_RIDE_MODE_START + 36, STR_MOVING_TO_END_OF = 1098, @@ -300,13 +318,21 @@ enum { STR_PLACE_SCENERY_TIP = 1159, STR_ADJUST_WATER_TIP = 1160, + STR_CANT_LOWER_WATER_LEVEL_HERE = 1166, + STR_CANT_RAISE_WATER_LEVEL_HERE = 1167, + STR_OPTIONS_TITLE = 1168, STR_SOUND_NONE = 1169, STR_BUILD_FOOTPATH_TIP = 1173, + + STR_BANNER_SIGN_IN_THE_WAY = 1174, + STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH = 1175, STR_CANT_BUILD_FOOTPATH_HERE = 1176, STR_CANT_REMOVE_FOOTPATH_FROM_HERE = 1177, + STR_LAND_SLOPE_UNSUITABLE = 1178, + STR_CANT_BUILD_THIS_UNDERWATER = 1180, STR_FOOTPATHS = 1181, STR_TYPE = 1182, STR_DIRECTION = 1183, @@ -359,6 +385,7 @@ enum { STR_SHOPS_STALLS_TIP = 1228, STR_ROTATE_OBJECTS_90 = 1327, + STR_LEVEL_LAND_REQUIRED = 1328, STR_LAUNCH_SPEED = 1329, STR_LAUNCH_SPEED_TIP = 1330, @@ -429,6 +456,9 @@ enum { STR_GUESTS = 1463, STR_STAFF = 1468, + + STR_RIDE_MUST_START_AND_END_WITH_STATIONS = 1469, + STR_STATION_NOT_LONG_ENOUGH = 1470, STR_SPEED = 1471, STR_SPEED_TIP = 1472, @@ -459,6 +489,8 @@ enum { STR_INCOME_AND_COSTS_TIP = 1695, STR_CUSTOMER_INFORMATION_TIP = 1696, + STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA = 1697, + STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA = 1698, STR_TOO_MANY_PEOPLE_IN_GAME = 1699, STR_HIRE_HANDYMAN = 1700, @@ -474,6 +506,7 @@ enum { STR_YES = 1710, STR_FIRE_STAFF_ID = 1711, + STR_INVALID_NAME_FOR_PARK = 1716, STR_CANT_RENAME_PARK = 1717, STR_PARK_NAME = 1718, STR_ENTER_PARK_NAME = 1719, @@ -491,6 +524,8 @@ enum { STR_RACE_WON_BY_GUEST = 1739, STR_RACE_WON_BY = 1740, + STR_NOT_YET_CONSTRUCTED = 1741, + STR_MAX_PEOPLE_ON_RIDE = 1742, STR_MAX_PEOPLE_ON_RIDE_TIP = 1743, @@ -713,6 +748,8 @@ enum { STR_CANT_DEMOLISH_RIDE = 2248, + STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS = 2252, + STR_RESEARCH_TRANSPORT_RIDES = 2253, STR_RESEARCH_GENTLE_RIDES = 2254, STR_RESEARCH_ROLLER_COASTERS = 2255, @@ -811,6 +848,7 @@ enum { STR_TILE_SMOOTHING_TIP = 2362, STR_GRIDLINES = 2363, STR_GRIDLINES_TIP = 2364, + STR_BANK_REFUSES_TO_INCREASE_LOAN = 2365, STR_CELSIUS = 2366, STR_FAHRENHEIT = 2367, //STR_NONE = 2368, @@ -844,6 +882,19 @@ enum { STR_OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE = STR_OBJECTIVE_NONE + 10, STR_OBJECTIVE_MONTHLY_FOOD_INCOME = STR_OBJECTIVE_NONE + 11, + STR_OBJECTIVE_DROPDOWN_NONE = 2397, + STR_OBJECTIVE_DROPDOWN_NUMBER_OF_GUESTS_AT_A_GIVEN_DATE = STR_OBJECTIVE_DROPDOWN_NONE + 1, + STR_OBJECTIVE_DROPDOWN_PARK_VALUE_AT_A_GIVEN_DATE = STR_OBJECTIVE_DROPDOWN_NONE + 2, + STR_OBJECTIVE_DROPDOWN_HAVE_FUN = STR_OBJECTIVE_DROPDOWN_NONE + 3, + STR_OBJECTIVE_DROPDOWN_BUILD_THE_BEST_RIDE_YOU_CAN = STR_OBJECTIVE_DROPDOWN_NONE + 4, + STR_OBJECTIVE_DROPDOWN_BUILD_10_ROLLER_COASTERS = STR_OBJECTIVE_DROPDOWN_NONE + 5, + STR_OBJECTIVE_DROPDOWN_NUMBER_OF_GUESTS_IN_PARK = STR_OBJECTIVE_DROPDOWN_NONE + 6, + STR_OBJECTIVE_DROPDOWN_MONTHLY_INCOME_FROM_RIDE_TICKETS = STR_OBJECTIVE_DROPDOWN_NONE + 7, + STR_OBJECTIVE_DROPDOWN_BUILD_10_ROLLER_COASTERS_OF_A_GIVEN_LENGTH = STR_OBJECTIVE_DROPDOWN_NONE + 8, + STR_OBJECTIVE_DROPDOWN_FINISH_BUILDING_5_ROLLER_COASTERS = STR_OBJECTIVE_DROPDOWN_NONE + 9, + STR_OBJECTIVE_DROPDOWN_REPAY_LOAN_AND_ACHIEVE_A_GIVEN_PARK_VALUE = STR_OBJECTIVE_DROPDOWN_NONE + 10, + STR_OBJECTIVE_DROPDOWN_MONTHLY_PROFIT_FROM_FOOD_MERCHANDISE = STR_OBJECTIVE_DROPDOWN_NONE + 11, + STR_MARKETING_CAMPAIGNS_IN_OPERATION = 2409, STR_MARKETING_CAMPAGINS_NONE = 2410, STR_MARKETING_CAMPAIGNS_AVAILABLE = 2411, @@ -939,6 +990,66 @@ enum { STR_SHORTCUT_DESCRIPTION_31 = 2524, STR_INDIVIDUAL_KEYS_BASE = 2525, + // Cheats + STR_CHEAT_TITLE = 5217, + STR_CHEAT_TITLE_FINANCIAL = 5345, + STR_CHEAT_TITLE_GUEST = 5346, + STR_CHEAT_TITLE_RIDE = 5347, + STR_CHEAT_TITLE_PARK = 5348, + + // Money + STR_CHEAT_5K_MONEY = 2760, + STR_CHEAT_PAY_ENTRANCE = 2761, + STR_CHEAT_CLEAR_LOAN = 5302, + STR_CHEAT_PAY_RIDES = 2762, + + // Guests + STR_CHEAT_HAPPY_GUESTS = 2764, + STR_CHEAT_LARGE_TRAM_GUESTS = 2765, + STR_CHEAT_NAUSEA = 5254, + STR_CHEAT_EXPLODE = 5285, + + // Misc. + STR_CHEAT_FREEZE_CLIMATE = 2767, + STR_CHEAT_UNFREEZE_CLIMATE = 2768, + STR_CHEAT_OPEN_PARK = 2769, + STR_CHEAT_CLOSE_PARK = 2770, + STR_CHEAT_ZERO_CLEARANCE = 2759, + STR_CHEAT_FORCE_SUN = 2757, + STR_CHEAT_FORCE_THUNDER = 2758, + STR_CHEAT_CLEAR_GRASS = 2752, + STR_CHEAT_MOWED_GRASS = 2753, + STR_CHEAT_WATER_PLANTS = 2754, + STR_CHEAT_FIX_VANDALISM = 2755, + STR_CHEAT_REMOVE_LITTER = 2756, + STR_CHEAT_WIN_SCENARIO = 2766, + STR_CHEAT_UNLOCK_PRICES = 5157, + STR_CHEAT_BUILD_IN_PAUSE_MODE = 5303, + + // Rides + STR_CHEAT_RENEW_RIDES = 5123, + STR_CHEAT_REMOVE_FLAGS = 5124, + STR_CHEAT_MAKE_DESTRUCTABLE = 5125, + STR_CHEAT_FIX_ALL_RIDES = 5132, + STR_CHEAT_410_HILL_LIFT = 5137, + STR_CHEAT_DISABLE_BRAKES_FAILURE = 5140, + STR_CHEAT_DISABLE_BREAKDOWNS = 5141, + + // Cheat tips + STR_CHEAT_TIP_5K_MONEY = 2681, + STR_CHEAT_TIP_PAY_ENTRY = 2682, + STR_CHEAT_TIP_CLEAR_LOAN = 5301, + STR_CHEAT_TIP_HAPPY_GUESTS = 2683, + STR_CHEAT_TIP_LARGE_TRAM_GUESTS = 2684, + STR_CHEAT_TIP_NAUSEA = 5255, + STR_CHEAT_TIP_EXPLODE = 5286, + + // Cheat tab tips + STR_FINANCIAL_CHEATS_TIP = 5178, + STR_GUEST_CHEATS_TIP = 5179, + STR_PARK_CHEATS_TIP = 5180, + STR_RIDE_CHEATS_TIP = 5181, + STR_SHORTCUT_ENTRY_FORMAT = 2781, STR_SHIFT_PLUS = 2782, STR_CTRL_PLUS = 2783, @@ -962,7 +1073,7 @@ enum { STR_MAP = 2802, STR_SHOW_GUESTS_ON_MAP_TIP = 2803, - STR_SHOW_STAFF_ON_MAP_TIP = 2803, + STR_SHOW_STAFF_ON_MAP_TIP = 2804, STR_SHOW_MAP_TIP = 2805, STR_PEEPS_DISGUSTED_BY_PATHS = 2806, @@ -1026,6 +1137,8 @@ enum { STR_MUSIC_ACKNOWLEDGEMENTS_ELLIPSIS = 2862, STR_MUSIC_ACKNOWLEDGEMENTS = 2863, + STR_TOO_MANY_BANNERS_IN_GAME = 2980, + STR_CHANGE_BANNER_TEXT_TIP = 2986, STR_SET_AS_NO_ENTRY_BANNER_TIP = 2987, STR_DEMOLISH_BANNER_TIP = 2988, @@ -1103,6 +1216,12 @@ enum { STR_SAME_PRICE_THROUGHOUT_PARK = 3071, STR_SAME_PRICE_THROUGHOUT_PARK_TIP = 3072, + STR_PARK_RATING_WARNING_4_WEEKS_REMAINING = 3073, + STR_PARK_RATING_WARNING_3_WEEKS_REMAINING = 3074, + STR_PARK_RATING_WARNING_2_WEEKS_REMAINING = 3075, + STR_PARK_RATING_WARNING_1_WEEK_REMAINING = 3076, + STR_PARK_HAS_BEEN_CLOSED_DOWN = 3077, + STR_PLAIN_ENTRANCE = 3078, STR_WOODEN_ENTRANCE = 3079, STR_CANVAS_TENT_ENTRANCE = 3080, @@ -1175,9 +1294,30 @@ enum { STR_LIST = 3159, + STR_UNABLE_TO_SELECT_THIS_OBJECT = 3176, + STR_UNABLE_TO_DE_SELECT_THIS_OBJECT = 3177, STR_AT_LEAST_ONE_PATH_OBJECT_MUST_BE_SELECTED = 3178, STR_INVALID_SELECTION_OF_OBJECTS = 3180, + STR_OBJECT_SELECTION = 3181, + STR_PARK_ENTRANCE_TYPE_MUST_BE_SELECTED = 3182, + STR_WATER_TYPE_MUST_BE_SELECTED = 3183, + STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS = 3184, + STR_OBJECT_SELECTION_SMALL_SCENERY = 3185, + STR_OBJECT_SELECTION_LARGE_SCENERY = 3186, + STR_OBJECT_SELECTION_WALLS_FENCES = 3187, + STR_OBJECT_SELECTION_PATH_SIGNS = 3188, + STR_OBJECT_SELECTION_FOOTPATHS = 3189, + STR_OBJECT_SELECTION_PATH_EXTRAS = 3190, + STR_OBJECT_SELECTION_SCENERY_GROUPS = 3191, + STR_OBJECT_SELECTION_PARK_ENTRANCE = 3192, + STR_OBJECT_SELECTION_WATER = 3193, + STR_OBJECT_SELECTION_SCENARIO_DESCRIPTION = 3194, + + STR_INVENTION_LIST = 3195, + + STR_RANDOM_SHUFFLE = 3199, + STR_RANDOM_SHUFFLE_TIP = 3200, STR_OBJECT_SELECTION_STEP = 3201, STR_LANDSCAPE_EDITOR_STEP = 3202, @@ -1208,7 +1348,57 @@ enum { STR_SET_STARTING_POSITIONS_TIP = 3228, + STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION = 3229, + STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_EACH_OTHER = 3230, + STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_THE_TOP_OF_THIS_LIFT_HILL = 3231, + + STR_SCENARIO_OPTIONS_FINANCIAL = 3232, + STR_SCENARIO_OPTIONS_GUESTS = 3233, + STR_SCENARIO_OPTIONS_PARK = 3234, + STR_SCENARIO_OPTIONS_FINANCIAL_TIP = 3235, + STR_SCENARIO_OPTIONS_GUESTS_TIP = 3236, + STR_SCENARIO_OPTIONS_PARK_TIP = 3237, + + STR_MAKE_PARK_NO_MONEY_TIP = 3239, + + STR_FORBID_MARKETING_TIP = 3245, + + STR_GUESTS_PREFER_LESS_INTENSE_RIDES = 3256, + STR_GUESTS_PREFER_LESS_INTENSE_RIDES_TIP = 3257, + STR_GUESTS_PREFER_MORE_INTENSE_RIDES = 3258, + STR_GUESTS_PREFER_MORE_INTENSE_RIDES_TIP = 3259, + + STR_PAY_FOR_PARK_PAY_FOR_RIDES_TIP = 3266, + STR_FORBID_TREE_REMOVAL = 3267, + STR_FORBID_TREE_REMOVAL_TIP = 3268, + STR_FORBID_LANDSCAPE_CHANGES = 3269, + STR_FORBID_LANDSCAPE_CHANGES_TIP = 3270, + STR_FORBID_HIGH_CONSTRUCTION = 3271, + STR_FORBID_HIGH_CONSTRUCTION_TIP = 3272, + STR_HARD_PARK_RATING = 3273, + STR_HARD_PARK_RATING_TIP = 3274, + STR_HARD_GUEST_GENERATION = 3275, + STR_HARD_GUEST_GENERATION_TIP = 3276, + + STR_SELECT_OBJECTIVE_AND_PARK_NAME_TIP = 3282, + STR_SELECT_RIDES_TO_BE_PRESERVED_TIP = 3283, + STR_OBJECTIVE_SELECTION = 3284, + STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP = 3286, + STR_SELECT_CLIMATE_TIP = 3288, + + STR_CLIMATE_COOL_AND_WET = 3290, + STR_CLIMATE_WARM = STR_CLIMATE_COOL_AND_WET + 1, + STR_CLIMATE_HOT_AND_DRY = STR_CLIMATE_COOL_AND_WET + 2, + STR_CLIMATE_COLD = STR_CLIMATE_COOL_AND_WET + 3, + + STR_CHANGE = 3294, + STR_CHANGE_NAME_OF_PARK_TIP = 3295, + STR_CHANGE_NAME_OF_SCENARIO_TIP = 3296, + STR_CHANGE_DETAIL_NOTES_ABOUT_PARK_SCENARIO_TIP = 3297, + + STR_NO_DETAILS_YET = 3317, + STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN = 3318, STR_UNABLE_TO_SAVE_SCENARIO_FILE = 3320, @@ -1221,6 +1411,9 @@ enum { STR_PARK_ENTRANCE_WRONG_DIRECTION_OR_NO_PATH = 3332, STR_SAVE_PLUGIN_DATA = 3333, STR_SAVE_PLUGIN_DATA_TIP = 3334, + STR_ROLLER_COASTER_DESIGNER_SELECT_RIDE_TYPES_VEHICLES = 3335, + STR_TRACK_DESIGNS_MANAGER_SELECT_RIDE_TYPE = 3336, + STR_SIX_FLAGS_PARK = 3337, STR_GAME_TOOLS = 3341, STR_SCENARIO_EDITOR = 3342, @@ -1228,19 +1421,46 @@ enum { STR_ROLLER_COASTER_DESIGNER = 3344, STR_TRACK_DESIGNS_MANAGER = 3345, + STR_TRACK_MANAGE_RENAME = 3348, + STR_TRACK_MANAGE_DELETE = 3349, + + STR_CANT_RENAME_TRACK_DESIGN = 3352, + + STR_ARE_YOU_SURE_YOU_WANT_TO_PERMANENTLY_DELETE_TRACK = 3357, + STR_CANT_DELETE_TRACK_DESIGN = 3358, STR_NO_TRACK_DESIGNS_OF_THIS_TYPE = 3359, STR_WARNING = 3360, STR_TOO_MANY_TRACK_DESIGNS_OF_THIS_TYPE = 3361, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING = 3362, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING_TIP = 3363, + STR_OBJECT_SELECTION_ADVANCED = 3364, + STR_OBJECT_SELECTION_ADVANCED_TIP = 3365, STR_MAP_RIDE = 3366, + STR_WARNING_TOO_MANY_OBJECTS_SELECTED = 3374, + STR_NOT_ALL_OBJECTS_IN_THIS_SCENERY_GROUP_COULD_BE_SELECTED = 3375, + STR_INSTALL_NEW_TRACK_DESIGN = 3376, + STR_INSTALL_NEW_TRACK_DESIGN_TIP = 3377, + STR_TUTORIAL_BEGINNERS = 3385, STR_TUTORIAL_CUSTOM_RIDES = 3386, STR_TUTORIAL_ROLLER_COASTER = 3387, + STR_OBJECTIVE_2_NONE = 2397, + STR_OBJECTIVE_2_NUMBER_OF_GUESTS_AT_A_GIVEN_DATE = STR_OBJECTIVE_2_NONE + 1, + STR_OBJECTIVE_2_PARK_VALUE_AT_A_GIVEN_DATE = STR_OBJECTIVE_2_NONE + 2, + STR_OBJECTIVE_2_HAVE_FUN = STR_OBJECTIVE_2_NONE + 3, + STR_OBJECTIVE_2_BUILD_THE_BEST_RIDE_YOU_CAN = STR_OBJECTIVE_2_NONE + 4, + STR_OBJECTIVE_2_BUILD_10_ROLLER_COASTERS = STR_OBJECTIVE_2_NONE + 5, + STR_OBJECTIVE_2_NUMBER_OF_GUESTS_IN_PARK = STR_OBJECTIVE_2_NONE + 6, + STR_OBJECTIVE_2_MONTHLY_INCOME_FROM_RIDE_TICKETS = STR_OBJECTIVE_2_NONE + 7, + STR_OBJECTIVE_2_BUILD_10_ROLLER_COASTERS_OF_A_GIVEN_LENGTH = STR_OBJECTIVE_2_NONE + 8, + STR_OBJECTIVE_2_FINISH_BUILDING_5_ROLLER_COASTERS = STR_OBJECTIVE_2_NONE + 9, + STR_OBJECTIVE_2_REPAY_LOAN_AND_ACHIEVE_A_GIVEN_PARK_VALUE = STR_OBJECTIVE_2_NONE + 10, + STR_OBJECTIVE_2_MONTHLY_PROFIT_FROM_FOOD_MERCHANDISE = STR_OBJECTIVE_2_NONE + 11, + STR_CLEAR_SCENERY_TIP = 3437, STR_CLEAR_SCENERY = 3439, @@ -1253,6 +1473,53 @@ enum { STR_SET_PATROL_AREA = 3445, STR_CLEAR_PATROL_AREA = 3446, + STR_OPENRCT2_BEGIN_STRING_ID = 5120, + + STR_TWITCH_NAME = 5164, + STR_TWITCH_PEEP_FOLLOWERS = 5165, + STR_TWITCH_PEEP_FOLLOWERS_TIP = 5166, + STR_TWITCH_FOLLOWERS_TRACK = 5167, + STR_TWITCH_FOLLOWERS_TRACK_TIP = 5168, + STR_TWITCH_PEEP_CHAT = 5169, + STR_TWITCH_PEEP_CHAT_TIP = 5170, + STR_TWITCH_CHAT_TRACK = 5171, + STR_TWITCH_CHAT_TRACK_TIP = 5172, + STR_TWITCH_CHAT_NEWS = 5173, + STR_TWITCH_CHAT_NEWS_TIP = 5174, + STR_TWITCH_NAME_DESC = 5175, + STR_TWITCH_ENABLE = 5176, + + STR_FULLSCREEN_MODE = 5177, + + STR_GIANT_SCREENSHOT = 5260, + + STR_CHEAT_SANDBOX_MODE = 5278, + STR_CHEAT_SANDBOX_MODE_DISABLE = 5279, + STR_CHEAT_SANDBOX_MODE_TIP = 5280, + + STR_DEBUG_TIP = 5311, + STR_DEBUG_DROPDOWN_CONSOLE = 5312, + STR_DEBUG_DROPDOWN_TILE_INSPECTOR = 5313, + STR_TILE_INSPECTOR_TITLE = 5314, + STR_TILE_INSPECTOR_TERRAIN_START = 5315, + STR_TILE_INSPECTOR_TERRAIN_EDGE_START = 5331, + STR_TILE_INSPECTOR_ENTRANCE_START = 5335, + STR_TILE_INSPECTOR_ELEMENT_TYPE = 5338, + STR_TILE_INSPECTOR_BASE_HEIGHT = 5339, + STR_TILE_INSPECTOR_CLEARANGE_HEIGHT = 5340, + STR_TILE_INSPECTOR_FLAGS = 5341, + STR_TILE_INSPECTOR_CHOOSE_MSG = 5342, + + STR_CHANGELOG_TITLE = 5344, + + STR_TITLE_SEQUENCE = 5304, + STR_TITLE_SEQUENCE_RCT1 = 5305, + STR_TITLE_SEQUENCE_RCT1_AA = 5306, + STR_TITLE_SEQUENCE_RCT1_AA_LL = 5307, + STR_TITLE_SEQUENCE_RCT2 = 5308, + STR_TITLE_SEQUENCE_OPENRCT2 = 5309, + STR_TITLE_SEQUENCE_RANDOM = 5310, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 }; diff --git a/src/localisation/user.c b/src/localisation/user.c index a832775f15..57358e4c65 100644 --- a/src/localisation/user.c +++ b/src/localisation/user.c @@ -18,10 +18,13 @@ * along with this program. If not, see . *****************************************************************************/ +#include "../addresses.h" #include "localisation.h" char *gUserStrings = (char*)0x0135A8F4; +static bool user_string_exists(const char *text); + /** * * rct2: 0x006C4209 @@ -31,15 +34,59 @@ void user_string_clear_all() memset(gUserStrings, 0, MAX_USER_STRINGS * USER_STRING_MAX_LENGTH); } +/** + * + * rct2: 0x006C421D + */ +rct_string_id user_string_allocate(int base, const char *text) +{ + int highBits = (base & 0x7F) << 9; + bool allowDuplicates = base & 0x80; + + if (!allowDuplicates && user_string_exists(text)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CHOSEN_NAME_IN_USE_ALREADY; + return 0; + } + + char *userString = gUserStrings; + for (int i = 0; i < MAX_USER_STRINGS; i++, userString += USER_STRING_MAX_LENGTH) { + if (userString[0] != 0) + continue; + + strncpy(userString, text, USER_STRING_MAX_LENGTH - 1); + return 0x8000 + (i | highBits); + } + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_MANY_NAMES_DEFINED; + return 0; +} + /** * * rct2: 0x006C42AC */ void user_string_free(rct_string_id id) { - if (id < 0x8000 || id >= 0x9000) + if (!is_user_string_id(id)) return; id %= MAX_USER_STRINGS; gUserStrings[id * USER_STRING_MAX_LENGTH] = 0; +} + +static bool user_string_exists(const char *text) +{ + char *userString = gUserStrings; + for (int i = 0; i < MAX_USER_STRINGS; i++, userString += USER_STRING_MAX_LENGTH) { + if (userString[0] == 0) + continue; + + if (strcmp(userString, text) == 0) + return true; + } + return false; +} + +bool is_user_string_id(rct_string_id stringId) +{ + return stringId >= 0x8000 && stringId < 0x9000; } \ No newline at end of file diff --git a/src/management/award.c b/src/management/award.c index 31b2fe356d..befba64a15 100644 --- a/src/management/award.c +++ b/src/management/award.c @@ -51,6 +51,8 @@ int _awardPositiveMap[] = { POSITIVE, // PARK_AWARD_BEST_GENTLE_RIDES }; +rct_award *gCurrentAwards = (rct_award*)RCT2_ADDRESS_AWARD_LIST; + int award_is_positive(int type) { return _awardPositiveMap[type]; @@ -288,7 +290,7 @@ static int award_is_deserved_best_food(int awardType, int activeAwardTypes) FOR_ALL_RIDES(i, ride) { if (ride->status != RIDE_STATUS_OPEN) continue; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x800000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_23)) continue; shops++; @@ -334,7 +336,7 @@ static int award_is_deserved_worst_food(int awardType, int activeAwardTypes) FOR_ALL_RIDES(i, ride) { if (ride->status != RIDE_STATUS_OPEN) continue; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x800000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_23)) continue; shops++; @@ -372,7 +374,7 @@ static int award_is_deserved_best_restrooms(int awardType, int activeAwardTypes) // Count open restrooms numRestrooms = 0; FOR_ALL_RIDES(i, ride) - if (ride->type == RIDE_TYPE_BATHROOM && ride->status == RIDE_STATUS_OPEN) + if (ride->type == RIDE_TYPE_TOILETS && ride->status == RIDE_STATUS_OPEN) numRestrooms++; // At least 4 open restrooms @@ -412,13 +414,13 @@ static int award_is_deserved_most_disappointing(int awardType, int activeAwardTy disappointingRides = 0; FOR_ALL_RIDES(i, ride) { - if (ride->excitement == 0xFFFF || ride->var_158 == 0xFF) + if (ride->excitement == 0xFFFF || ride->popularity == 0xFF) continue; countedRides++; - // Satification maybe? - if (ride->var_158 <= 6) + // Unpopular + if (ride->popularity <= 6) disappointingRides++; } @@ -459,9 +461,9 @@ static int award_is_deserved_best_custom_designed_rides(int awardType, int activ customDesignedRides = 0; FOR_ALL_RIDES(i, ride) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x10000000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) continue; - if (ride->lifecycle_flags & 0x40000) + if (ride->lifecycle_flags & RIDE_LIFECYCLE_18) continue; if (ride->excitement < RIDE_RATING(5, 50)) continue; @@ -488,7 +490,7 @@ static int award_is_deserved_most_dazzling_ride_colours(int awardType, int activ countedRides = 0; colourfulRides = 0; FOR_ALL_RIDES(i, ride) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x10000000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) continue; countedRides++; @@ -519,7 +521,7 @@ static int award_is_deserved_most_confusing_layout(int awardType, int activeAwar continue; peepsCounted++; - if (peep->thoughts[0].var_2 <= 5 && peep->thoughts[0].type == PEEP_THOUGHT_TYPE_LOST || peep->thoughts[0].type == PEEP_THOUGHT_TYPE_CANT_FIND) + if (peep->thoughts[0].var_2 <= 5 && (peep->thoughts[0].type == PEEP_THOUGHT_TYPE_LOST || peep->thoughts[0].type == PEEP_THOUGHT_TYPE_CANT_FIND)) peepsLost++; } @@ -581,7 +583,7 @@ void award_reset() { int i; for (i = 0; i < MAX_AWARDS; i++) - RCT2_ADDRESS(RCT2_ADDRESS_AWARD_LIST, rct_award)[i].time = 0; + gCurrentAwards[i].time = 0; } /** @@ -591,9 +593,6 @@ void award_reset() void award_update_all() { int i, activeAwardTypes, freeAwardEntryIndex; - rct_award *awards; - - awards = RCT2_ADDRESS(RCT2_ADDRESS_AWARD_LIST, rct_award); // Only add new awards if park is open if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) { @@ -601,8 +600,8 @@ void award_update_all() activeAwardTypes = 0; freeAwardEntryIndex = -1; for (i = 0; i < MAX_AWARDS; i++) { - if (awards[i].time != 0) - activeAwardTypes |= (1 << awards[i].type); + if (gCurrentAwards[i].time != 0) + activeAwardTypes |= (1 << gCurrentAwards[i].type); else if (freeAwardEntryIndex == -1) freeAwardEntryIndex = i; } @@ -618,8 +617,8 @@ void award_update_all() // Check if award is deserved if (award_is_deserved(awardType, activeAwardTypes)) { // Add award - awards[freeAwardEntryIndex].type = awardType; - awards[freeAwardEntryIndex].time = 5; + gCurrentAwards[freeAwardEntryIndex].type = awardType; + gCurrentAwards[freeAwardEntryIndex].time = 5; news_item_add_to_queue(NEWS_ITEM_AWARD, STR_NEWS_ITEM_AWARD_MOST_UNTIDY + awardType, 0); window_invalidate_by_class(WC_PARK_INFORMATION); } @@ -628,7 +627,7 @@ void award_update_all() // Decrease award times for (i = 0; i < MAX_AWARDS; i++) - if (awards[i].time != 0) - if (--awards[i].time == 0) + if (gCurrentAwards[i].time != 0) + if (--gCurrentAwards[i].time == 0) window_invalidate_by_class(WC_PARK_INFORMATION); -} \ No newline at end of file +} diff --git a/src/management/award.h b/src/management/award.h index 8e7c965f50..faab09d43c 100644 --- a/src/management/award.h +++ b/src/management/award.h @@ -51,6 +51,8 @@ enum { #define MAX_AWARDS 4 +extern rct_award *gCurrentAwards; + int award_is_positive(int type); void award_reset(); void award_update_all(); diff --git a/src/management/finance.c b/src/management/finance.c index 8eccfd85b5..00db151578 100644 --- a/src/management/finance.c +++ b/src/management/finance.c @@ -19,7 +19,9 @@ *****************************************************************************/ #include "../addresses.h" +#include "../game.h" #include "../interface/window.h" +#include "../localisation/localisation.h" #include "../peep/peep.h" #include "../ride/ride.h" #include "../world/park.h" @@ -42,6 +44,8 @@ const money32 research_cost_table[4] = { MONEY(400,00) // Maximum funding }; +int dword_988E60[] = { 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 }; + /** * Pay an amount of money. * rct2: 0x069C674 @@ -56,13 +60,12 @@ void finance_payment(money32 amount, rct_expenditure_type type) //overflow check RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(new_money); RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[type] -= amount; - if (RCT2_ADDRESS(0x00988E60, uint32)[type] & 1) + if (dword_988E60[type] & 1) RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_EXPENDITURE, money32) -= amount; // Cumulative amount of money spent this day - RCT2_GLOBAL(0x009A9804, uint32) |= 1; // money dirty flag + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint32) |= BTM_TB_DIRTY_FLAG_MONEY; window_invalidate_by_class(WC_FINANCES); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); } /** @@ -124,15 +127,15 @@ void finance_pay_ride_upkeep() FOR_ALL_RIDES(i, ride) { if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED)) { ride->build_date = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); - ride->var_196 = 25855; // durability? + ride->reliability = RIDE_INITIAL_RELIABILITY; } if (ride->status != RIDE_STATUS_CLOSED && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { sint16 upkeep = ride->upkeep_cost; if (upkeep != -1) { ride->total_profit -= upkeep; - ride->var_14D |= 2; - finance_payment(upkeep, RCT2_EXPENDITURE_TYPE_RIDE_UPKEEP); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + finance_payment(upkeep, RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS); } } } @@ -154,7 +157,8 @@ void finance_reset_history() */ void finance_init() { - for (short i = 0; i < 56; i++) { + // It only initializes the first month + for (uint32 i = 0; i < RCT_EXPENDITURE_TYPE_COUNT; i++) { RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[i] = 0; } @@ -240,7 +244,7 @@ void sub_69E869() { // This subroutine is loan related and is used for cheat detection sint32 value = 0x70093A; - value -= RCT2_GLOBAL(0x013573DC, money32); // Cheat detection + value -= RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32); value = ror32(value, 5); value -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32); value = ror32(value, 7); @@ -248,3 +252,99 @@ void sub_69E869() value = ror32(value, 3); RCT2_GLOBAL(0x013587C4, sint32) = value; } + +void finance_set_loan(money32 loan) +{ + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, loan, GAME_COMMAND_SET_CURRENT_LOAN, 0, 0); +} + +money32 finance_get_initial_cash() +{ + return RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32); +} + +money32 finance_get_current_loan() +{ + return RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32); +} + +money32 finance_get_maximum_loan() +{ + return RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32); +} + +money32 finance_get_current_cash() +{ + return DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32)); +} + +/** + * + * rct2: 0x0069DFB3 + */ +void game_command_set_current_loan(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + money32 money, loanDifference, currentLoan; + money32 newLoan = *edx; + + currentLoan = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32); + money = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32)); + loanDifference = currentLoan - newLoan; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_INTEREST * 4; + if (newLoan > currentLoan) { + if (newLoan > RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BANK_REFUSES_TO_INCREASE_LOAN; + *ebx = MONEY32_UNDEFINED; + return; + } + } else { + if (loanDifference > money) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NOT_ENOUGH_CASH_AVAILABLE; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + money -= loanDifference; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = newLoan; + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) = money; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32) = ENCRYPT_MONEY(money); + sub_69E869(); + + window_invalidate_by_class(WC_FINANCES); + RCT2_GLOBAL(0x009A9804, uint16) |= 1; + } + + *ebx = 0; +} + +/** +* Shift the expenditure table history one month to the left +* If the table is full, acumulate the sum of the oldest month first +* rct2: 0x0069DEAD +*/ + +void finance_shift_expenditure_table() { + + // If EXPENDITURE_TABLE_MONTH_COUNT months have passed then is full, sum the oldest month + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) >= EXPENDITURE_TABLE_MONTH_COUNT) { + money32 sum = 0; + for (uint32 i = EXPENDITURE_TABLE_TOTAL_COUNT - RCT_EXPENDITURE_TYPE_COUNT; i < EXPENDITURE_TABLE_TOTAL_COUNT; i++) { + sum += RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[i]; + } + RCT2_GLOBAL(0x013587D0, money32) += sum; + } + // Shift the table + for (uint32 i = EXPENDITURE_TABLE_TOTAL_COUNT - 1; i >= RCT_EXPENDITURE_TYPE_COUNT; i--) { + RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[i] = + RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[i - RCT_EXPENDITURE_TYPE_COUNT]; + } + // Zero the beggining of the table, which is the new month + for (uint32 i = 0; i < RCT_EXPENDITURE_TYPE_COUNT; i++) { + RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[i] = 0; + } + // Invalidate the expenditure table window + window_invalidate_by_number(0x1C, 0); +} \ No newline at end of file diff --git a/src/management/finance.h b/src/management/finance.h index f87998ab15..e16d04d787 100644 --- a/src/management/finance.h +++ b/src/management/finance.h @@ -26,12 +26,26 @@ typedef int rct_expenditure_type; enum { - RCT2_EXPENDITURE_TYPE_RIDE_UPKEEP = 1, - RCT_EXPENDITURE_TYPE_WAGES = 10, - RCT_EXPENDITURE_TYPE_RESEARCH = 12, - RCT_EXPENDITURE_TYPE_INTEREST = 13 + RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION, + RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS, + RCT_EXPENDITURE_TYPE_LAND_PURCHASE, + RCT_EXPENDITURE_TYPE_LANDSCAPING, + RCT_EXPENDITURE_TYPE_PARK_ENTRANCE_TICKETS, + RCT_EXPENDITURE_TYPE_PARK_RIDE_TICKETS, + RCT_EXPENDITURE_TYPE_SHOP_SHOP_SALES, + RCT_EXPENDITURE_TYPE_SHOP_STOCK, + RCT_EXPENDITURE_TYPE_FOODDRINK_SALES, + RCT_EXPENDITURE_TYPE_FOODDRINK_STOCK, + RCT_EXPENDITURE_TYPE_WAGES, + RCT_EXPENDITURE_TYPE_MARKETING, + RCT_EXPENDITURE_TYPE_RESEARCH, + RCT_EXPENDITURE_TYPE_INTEREST, + RCT_EXPENDITURE_TYPE_COUNT }; +#define EXPENDITURE_TABLE_MONTH_COUNT 16 +#define EXPENDITURE_TABLE_TOTAL_COUNT (EXPENDITURE_TABLE_MONTH_COUNT * RCT_EXPENDITURE_TYPE_COUNT) + extern const money32 research_cost_table[4]; void finance_payment(money32 amount, rct_expenditure_type type); @@ -42,6 +56,14 @@ void finance_pay_ride_upkeep(); void finance_reset_history(); void finance_init(); void finance_update_daily_profit(); +void finance_shift_expenditure_table(); void sub_69E869(); +void finance_set_loan(money32 loan); +money32 finance_get_initial_cash(); +money32 finance_get_current_loan(); +money32 finance_get_maximum_loan(); +money32 finance_get_current_cash(); +void game_command_set_current_loan(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); + #endif \ No newline at end of file diff --git a/src/management/marketing.c b/src/management/marketing.c index c8e56269e0..d60a351c73 100644 --- a/src/management/marketing.c +++ b/src/management/marketing.c @@ -19,8 +19,10 @@ *****************************************************************************/ #include "../addresses.h" +#include "../game.h" #include "../interface/window.h" #include "../localisation/localisation.h" +#include "../management/finance.h" #include "../ride/ride.h" #include "marketing.h" #include "news_item.h" @@ -36,6 +38,9 @@ const money16 AdvertisingCampaignPricePerWeek[] = { const int advertisingCampaignGuestGenerationProbabilities[] = { 400, 300, 200, 200, 250, 200 }; +uint8 *gMarketingCampaignDaysLeft = RCT2_ADDRESS(0x01358102, uint8); +uint8 *gMarketingCampaignRideIndex = RCT2_ADDRESS(0x01358116, uint8); + int marketing_get_campaign_guest_generation_probability(int campaign) { int probability = advertisingCampaignGuestGenerationProbabilities[campaign]; @@ -52,7 +57,7 @@ int marketing_get_campaign_guest_generation_probability(int campaign) probability /= 8; break; case ADVERTISING_CAMPAIGN_RIDE_FREE: - ride = &g_ride_list[RCT2_ADDRESS(0x01358116, uint8)[campaign]]; + ride = &g_ride_list[gMarketingCampaignRideIndex[campaign]]; if (ride->price < 3) probability /= 8; break; @@ -68,33 +73,33 @@ int marketing_get_campaign_guest_generation_probability(int campaign) void marketing_update() { for (int campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) { - uint8 campaign_weeks_left = RCT2_ADDRESS(0x01358102, uint8)[campaign]; - if (campaign_weeks_left == 0) + int active = (gMarketingCampaignDaysLeft[campaign] & CAMPAIGN_ACTIVE_FLAG) != 0; + if (gMarketingCampaignDaysLeft[campaign] == 0) continue; window_invalidate_by_class(WC_FINANCES); - // High bit marks the campaign as inactive, on first check the campaign is set actice + // High bit marks the campaign as inactive, on first check the campaign is set active // this makes campaigns run a full x weeks even when started in the middle of a week - RCT2_ADDRESS(0x01358102, uint8)[campaign] &= ~(1 << 7); - if (campaign_weeks_left & (1 << 7)) + gMarketingCampaignDaysLeft[campaign] &= ~CAMPAIGN_ACTIVE_FLAG; + if (active) continue; - RCT2_ADDRESS(0x01358102, uint8)[campaign]--; - if (campaign_weeks_left - 1 != 0) + if (--gMarketingCampaignDaysLeft[campaign] != 0) continue; - int campaign_item = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + int campaignItem = gMarketingCampaignRideIndex[campaign]; // This sets the string parameters for the marketing types that have an argument. if (campaign == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign == ADVERTISING_CAMPAIGN_RIDE) { - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x01362942 + 304 * campaign_item, uint16); - RCT2_GLOBAL(0x013CE954, uint32) = RCT2_GLOBAL(0x01362944 + 152 * campaign_item, uint32); + rct_ride* ride = GET_RIDE(campaignItem); + RCT2_GLOBAL(0x013CE952, uint16) = ride->name; + RCT2_GLOBAL(0x013CE954, uint32) = ride->name_arguments; } else if (campaign == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) { - campaign_item += 2016; - if (campaign_item >= 2048) - campaign_item += 96; - RCT2_GLOBAL(0x013CE952, uint16) = campaign_item; + campaignItem += 2016; + if (campaignItem >= 2048) + campaignItem += 96; + RCT2_GLOBAL(0x013CE952, uint16) = campaignItem; } news_item_add_to_queue(NEWS_ITEM_MONEY, STR_MARKETING_FINISHED_BASE + campaign, 0); @@ -111,8 +116,8 @@ void marketing_set_guest_campaign(rct_peep *peep, int campaign) case ADVERTISING_CAMPAIGN_RIDE_FREE: peep->item_standard_flags |= PEEP_ITEM_VOUCHER; peep->voucher_type = VOUCHER_TYPE_RIDE_FREE; - peep->voucher_arguments = RCT2_ADDRESS(0x01358116, uint8)[campaign]; - peep->guest_heading_to_ride_id = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->voucher_arguments = gMarketingCampaignRideIndex[campaign]; + peep->guest_heading_to_ride_id = gMarketingCampaignRideIndex[campaign]; peep->var_C6 = 240; break; case ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE: @@ -122,13 +127,46 @@ void marketing_set_guest_campaign(rct_peep *peep, int campaign) case ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE: peep->item_standard_flags |= PEEP_ITEM_VOUCHER; peep->voucher_type = VOUCHER_TYPE_FOOD_OR_DRINK_FREE; - peep->voucher_arguments = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->voucher_arguments = gMarketingCampaignRideIndex[campaign]; break; case ADVERTISING_CAMPAIGN_PARK: break; case ADVERTISING_CAMPAIGN_RIDE: - peep->guest_heading_to_ride_id = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->guest_heading_to_ride_id = gMarketingCampaignRideIndex[campaign]; peep->var_C6 = 240; break; } +} + +void marketing_start_campaign(int type, int rideOrItem, int numWeeks) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_START_MARKETING_CAMPAIGN; + game_do_command(0, (numWeeks << 8) | GAME_COMMAND_FLAG_APPLY, 0, (rideOrItem << 8) | type, GAME_COMMAND_START_MARKETING_CAMPAIGN, 0, 0); +} + +/** + * + * rct2: 0x0069E73C + */ +void game_command_start_campaign(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + int type = *edx & 0xFF; + int rideOrItem = (*edx >> 8) & 0xFF; + int numWeeks = (*ebx >> 8) & 0xFF; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_MARKETING * 4; + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3048; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + gMarketingCampaignDaysLeft[type] = numWeeks | CAMPAIGN_ACTIVE_FLAG; + gMarketingCampaignRideIndex[type] = rideOrItem; + + window_invalidate_by_class(WC_FINANCES); + } + + *ebx = numWeeks * AdvertisingCampaignPricePerWeek[type]; } \ No newline at end of file diff --git a/src/management/marketing.h b/src/management/marketing.h index 6435256cb4..33abb47560 100644 --- a/src/management/marketing.h +++ b/src/management/marketing.h @@ -41,10 +41,16 @@ enum{ VOUCHER_TYPE_FOOD_OR_DRINK_FREE, }; +#define CAMPAIGN_ACTIVE_FLAG (1 << 7) + extern const money16 AdvertisingCampaignPricePerWeek[6]; +extern uint8 *gMarketingCampaignDaysLeft; +extern uint8 *gMarketingCampaignRideIndex; int marketing_get_campaign_guest_generation_probability(int campaign); void marketing_update(); void marketing_set_guest_campaign(rct_peep *peep, int campaign); +void marketing_start_campaign(int type, int rideOrItem, int numWeeks); +void game_command_start_campaign(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); #endif \ No newline at end of file diff --git a/src/management/news_item.c b/src/management/news_item.c index 6c315cdbb0..188f17ba6e 100644 --- a/src/management/news_item.c +++ b/src/management/news_item.c @@ -28,6 +28,8 @@ #include "../world/sprite.h" #include "news_item.h" +rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); + void window_game_bottom_toolbar_invalidate_news_item(); static int news_item_get_new_history_slot(); @@ -61,13 +63,15 @@ void news_item_update_current() ax = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAY, sint16); bx = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MONTH, sint16); + + // Cheat detection if (bx != RCT2_GLOBAL(0x009DEA6B, sint16)) { bx--; if (bx == 0) bx = 12; - if (bx != RCT2_GLOBAL(0x009DEA6B, sint16) || ax == 1) { + if (bx != RCT2_GLOBAL(0x009DEA6B, sint16) || ax != 1) { // loc_66E2AE - RCT2_GLOBAL(0x013573DC, sint32) = 10000; + RCT2_GLOBAL(0x013573DC, sint32) -= 10000; if (RCT2_GLOBAL(0x013573DC, sint32) >= 0) RCT2_GLOBAL(0x013573DC, sint32) = -RCT2_GLOBAL(0x013573DC, sint32); } @@ -76,7 +80,7 @@ void news_item_update_current() ax--; if (ax != RCT2_GLOBAL(0x009DEA69, sint16)) { // loc_66E2AE - RCT2_GLOBAL(0x013573DC, sint32) = 10000; + RCT2_GLOBAL(0x013573DC, sint32) -= 10000; if (RCT2_GLOBAL(0x013573DC, sint32) >= 0) RCT2_GLOBAL(0x013573DC, sint32) = -RCT2_GLOBAL(0x013573DC, sint32); } @@ -245,6 +249,15 @@ void news_item_get_subject_location(int type, int subject, int *x, int *y, int * * @param c (ecx) **/ void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc) +{ + char *buffer = (char*)0x0141EF68; + void *args = (void*)0x013CE952; + + format_string(buffer, string_id, args); // overflows possible? + news_item_add_to_queue_raw(type, buffer, assoc); +} + +void news_item_add_to_queue_raw(uint8 type, const char *text, uint32 assoc) { int i = 0; rct_news_item *newsItem = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); @@ -264,10 +277,8 @@ void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc) newsItem->ticks = 0; newsItem->month_year = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); newsItem->day = ((days_in_month[(newsItem->month_year & 7)] * RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16)) >> 16) + 1; - - format_string((char*)0x0141EF68, string_id, (void*)0x013CE952); // overflows possible? - newsItem->colour = ((char*)0x0141EF68)[0]; - strncpy(newsItem->text, (char*)0x0141EF68, 255); + newsItem->colour = text[0]; + strncpy(newsItem->text, text + 1, 254); newsItem->text[254] = 0; // blatant disregard for what happens on the last element. @@ -318,20 +329,21 @@ void news_item_open_subject(int type, int subject) window = window_find_by_class(WC_TOP_TOOLBAR); if (window != NULL) { window_invalidate(window); - if (tool_set(window, 9, 0)){ - RCT2_CALLPROC_X(0x006E1172, (subject & 0xFFFF), 0, subject, 0, 0, 0, 0); + if (!tool_set(window, 9, 0)) { + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + window_scenery_open(); } - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; - window_scenery_open(); } } // Switch to new scenery tab - RCT2_CALLPROC_X(0x006E1172, (subject & 0xFFFF), 0, subject, 0, 0, 0, 0); + window = window_find_by_class(WC_SCENERY); + if (window != NULL) + window_event_mouse_down_call(window, 4 + subject); break; case NEWS_ITEM_PEEPS: // Open guest list to right tab - RCT2_CALLPROC_X(0x006993BA, 3, subject, 0, 0, 0, 0, 0); + window_guest_list_open_with_filter(3, subject);; break; case NEWS_ITEM_AWARD: window_park_awards_open(); @@ -341,3 +353,29 @@ void news_item_open_subject(int type, int subject) break; } } + +/** + * rct2: 0x0066E407 + */ +void news_item_disable_news(uint8 type, uint32 assoc) { + rct_news_item* newsItem = newsItems; + while (newsItem->type != NEWS_ITEM_NULL) { + if (type == newsItem->type && assoc == newsItem->assoc) { + newsItem->flags |= 0x1; + if (newsItem == RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item)) { + window_game_bottom_toolbar_invalidate_news_item(); + } + } + newsItem++; + } + + newsItem = &newsItems[11]; //0x13CB2D8 + while (newsItem->type != NEWS_ITEM_NULL) { + if (type == newsItem->type && assoc == newsItem->assoc) { + newsItem->flags |= 0x1; + window_invalidate_by_class(WC_RECENT_NEWS); + } + newsItem++; + } +} + diff --git a/src/management/news_item.h b/src/management/news_item.h index 8b48e61b6b..34d4459147 100644 --- a/src/management/news_item.h +++ b/src/management/news_item.h @@ -57,6 +57,8 @@ void news_item_update_current(); void news_item_close_current(); void news_item_get_subject_location(int type, int subject, int *x, int *y, int *z); void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc); +void news_item_add_to_queue_raw(uint8 type, const char *text, uint32 assoc); void news_item_open_subject(int type, int subject); +void news_item_disable_news(uint8 type, uint32 assoc); #endif diff --git a/src/management/research.c b/src/management/research.c index 4aac4d1b3e..f44ed4c5b2 100644 --- a/src/management/research.c +++ b/src/management/research.c @@ -19,21 +19,25 @@ *****************************************************************************/ #include "../addresses.h" +#include "../game.h" #include "../interface/window.h" #include "../localisation/date.h" +#include "../management/finance.h" +#include "../scenario.h" #include "../world/scenery.h" #include "news_item.h" #include "research.h" -#include "../scenario.h" const int _researchRate[] = { 0, 160, 250, 400 }; // 0x01358844[500] -extern rct_research_item *gResearchItems = (rct_research_item*)RCT2_RESEARCH_ITEMS; +rct_research_item *gResearchItems = (rct_research_item*)RCT2_RESEARCH_ITEMS; // 0x00EE787C uint8 gResearchUncompletedCategories; +bool gSilentResearch = false; + /** * * rct2: 0x006671AD, part of 0x00667132 @@ -42,7 +46,7 @@ void research_reset_items() { gResearchItems[0].entryIndex = RESEARCHED_ITEMS_SEPERATOR; gResearchItems[1].entryIndex = RESEARCHED_ITEMS_END; - gResearchItems[2].entryIndex = -3; + gResearchItems[2].entryIndex = RESEARCHED_ITEMS_END_2; } /** @@ -53,10 +57,9 @@ void research_update_uncompleted_types() { int uncompletedResearchTypes = 0; rct_research_item *researchItem = gResearchItems; - while (researchItem->entryIndex != -1) - researchItem++; - researchItem++; - for (; researchItem->entryIndex != -2; researchItem++) + while (researchItem++->entryIndex != RESEARCHED_ITEMS_SEPERATOR); + + for (; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) uncompletedResearchTypes |= (1 << researchItem->category); gResearchUncompletedCategories = uncompletedResearchTypes; @@ -126,8 +129,10 @@ static void research_next_design() continue; } else { RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = RESEARCH_STAGE_INITIAL_RESEARCH; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = RESEARCH_STAGE_FINISHED_ALL; research_invalidate_related_windows(); + // Reset funding to 0 if no more rides. + research_set_funding(0); return; } } else if (ignoreActiveResearchTypes || (activeResearchTypes & (1 << researchItem->category))) { @@ -157,7 +162,7 @@ static void research_next_design() */ void research_finish_item(sint32 entryIndex) { - int i, ebx, ecx, rideEntryIndex, subSceneryEntryIndex; + int i, ebx, base_ride_type, rideEntryIndex, subSceneryEntryIndex; rct_ride_type *rideEntry, *rideEntry2; rct_scenery_set_entry *scenerySetEntry; @@ -165,36 +170,37 @@ void research_finish_item(sint32 entryIndex) research_invalidate_related_windows(); if (entryIndex >= 0x10000) { // Ride - ecx = (entryIndex >> 8) & 0xFF; + base_ride_type = (entryIndex >> 8) & 0xFF; rideEntryIndex = entryIndex & 0xFF; rideEntry = GET_RIDE_ENTRY(rideEntryIndex); - RCT2_ADDRESS(0x01357404, uint32)[ecx >> 5] |= (1 << (ecx & 0x1F)); - RCT2_ADDRESS(0x01357444, uint32)[ecx] = RCT2_ADDRESS(0x0097C468, uint32)[ecx]; - RCT2_ADDRESS(0x01357644, uint32)[ecx] = RCT2_ADDRESS(0x0097C5D4, uint32)[ecx]; - if (RCT2_GLOBAL(0x0097D4F2 + (ecx * 8), uint16) & 8) { - ebx = RCT2_GLOBAL(0x0097D4F5 + (ecx * 8), uint8); + RCT2_ADDRESS(0x01357404, uint32)[base_ride_type >> 5] |= (1 << (base_ride_type & 0x1F)); + RCT2_ADDRESS(0x01357444, uint32)[base_ride_type] = RCT2_ADDRESS(0x0097C468, uint32)[base_ride_type]; + RCT2_ADDRESS(0x01357644, uint32)[base_ride_type] = RCT2_ADDRESS(0x0097C5D4, uint32)[base_ride_type]; + if (RCT2_GLOBAL(0x0097D4F2 + (base_ride_type * 8), uint16) & 8) { + ebx = RCT2_GLOBAL(0x0097D4F5 + (base_ride_type * 8), uint8); RCT2_ADDRESS(0x01357444, uint32)[ebx] = RCT2_ADDRESS(0x0097C468, uint32)[ebx]; RCT2_ADDRESS(0x01357644, uint32)[ebx] = RCT2_ADDRESS(0x0097C5D4, uint32)[ebx]; } RCT2_ADDRESS(0x001357424, uint32)[rideEntryIndex >> 5] |= 1 << (rideEntryIndex & 0x1F); - if (!(rideEntry->var_008 & 0x2000)) { + if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE)) { for (i = 0; i < 128; i++) { rideEntry2 = GET_RIDE_ENTRY(i); if (rideEntry2 == (rct_ride_type*)-1) continue; - if (rideEntry2->var_008 & 0x2000) + if (rideEntry2->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE) continue; - if (rideEntry2->var_00C == ecx || rideEntry2->var_00D == ecx || rideEntry2->var_00E == ecx) + if (rideEntry2->ride_type[0] == base_ride_type || rideEntry2->ride_type[1] == base_ride_type || rideEntry2->ride_type[2] == base_ride_type) RCT2_ADDRESS(0x001357424, uint32)[i >> 5] |= 1 << (i & 0x1F); } } // I don't think 0x009AC06C is ever not 0, so probably redundant if (RCT2_GLOBAL(0x009AC06C, uint8) == 0) { - RCT2_GLOBAL(0x013CE952, rct_string_id) = rideEntry->var_008 & 0x1000 ? - rideEntry->name : ecx + 2; - news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2249, entryIndex); + RCT2_GLOBAL(0x013CE952, rct_string_id) = rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME ? + rideEntry->name : base_ride_type + 2; + if (!gSilentResearch) + news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2249, entryIndex); } research_invalidate_related_windows(); @@ -209,7 +215,8 @@ void research_finish_item(sint32 entryIndex) // I don't think 0x009AC06C is ever not 0, so probably redundant if (RCT2_GLOBAL(0x009AC06C, uint8) == 0) { RCT2_GLOBAL(0x013CE952, rct_string_id) = scenerySetEntry->name; - news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2250, entryIndex); + if (!gSilentResearch) + news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2250, entryIndex); } research_invalidate_related_windows(); @@ -262,26 +269,29 @@ void research_update() } } -/* rct2: 0x684AC3*/ +/** + * + * rct2: 0x00684AC3 + */ void sub_684AC3(){ rct_research_item* research = gResearchItems; - for (; research->entryIndex != -2; research++); + for (; research->entryIndex != RESEARCHED_ITEMS_END; research++); research++; - for (; research->entryIndex != -3; research += 2){ + for (; research->entryIndex != RESEARCHED_ITEMS_END_2; research += 2){ if (scenario_rand() & 1) continue; - rct_research_item* edx; rct_research_item* ebp; - for (rct_research_item* inner_research = gResearchItems; inner_research->entryIndex != -2; inner_research++){ + rct_research_item* inner_research = gResearchItems; + do{ if (research->entryIndex == inner_research->entryIndex){ edx = inner_research; } if ((research + 1)->entryIndex == inner_research->entryIndex){ ebp = inner_research; } - } + } while ((inner_research++)->entryIndex != RESEARCHED_ITEMS_END); edx->entryIndex = research->entryIndex; ebp->entryIndex = (research + 1)->entryIndex; @@ -310,11 +320,223 @@ void sub_684AC3(){ } - for (research = gResearchItems; research->entryIndex != -1; research++){ + for (research = gResearchItems; research->entryIndex != RESEARCHED_ITEMS_SEPERATOR; research++){ research_finish_item(research->entryIndex); } RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32) = -1; RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = 0; RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; +} + +/** + * + * rct2: 0x0068585B + */ +void research_remove_non_separate_vehicle_types() +{ + rct_research_item *researchItem, *researchItem2; + + researchItem = gResearchItems; + while ((researchItem + 1)->entryIndex != RESEARCHED_ITEMS_END) { + researchItem++; + } + + do { + loopBeginning: + if ( + researchItem != gResearchItems && + researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR && + researchItem->entryIndex != RESEARCHED_ITEMS_END && + researchItem->entryIndex >= 0x10000 + ) { + rct_ride_type *rideEntry = GET_RIDE_ENTRY(researchItem->entryIndex & 0xFF); + if (!(rideEntry->flags & + (RIDE_ENTRY_FLAG_SEPERATE_RIDE | + RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME))) { + // Check if ride type already exists further up for a vehicle type that isn't displayed as a ride + researchItem2 = researchItem - 1; + do { + if ( + researchItem2->entryIndex != RESEARCHED_ITEMS_SEPERATOR && + researchItem2->entryIndex >= 0x10000 + ) { + rideEntry = GET_RIDE_ENTRY(researchItem2->entryIndex & 0xFF); + if (!(rideEntry->flags & + (RIDE_ENTRY_FLAG_SEPERATE_RIDE | + RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME))) { + + if (((researchItem->entryIndex >> 8) & 0xFF) == ((researchItem2->entryIndex >> 8) & 0xFF)) { + // Remove item + researchItem2 = researchItem; + do { + *researchItem2 = *(researchItem2 + 1); + } while ((researchItem2++)->entryIndex != RESEARCHED_ITEMS_END_2); + goto loopBeginning; + } + } + } + } while ((researchItem2--) != gResearchItems); + } + } + } while ((researchItem--) != gResearchItems); +} + +/** + * + * rct2: 0x006857FA + */ +static void research_insert_unresearched(int entryIndex, int category) +{ + rct_research_item *researchItem, *researchItem2; + + researchItem = gResearchItems; + do { + if (researchItem->entryIndex == RESEARCHED_ITEMS_END) { + // Insert slot + researchItem2 = researchItem; + while (researchItem2->entryIndex != RESEARCHED_ITEMS_END_2) { + researchItem2++; + } + memmove(researchItem + 1, researchItem, (researchItem2 - researchItem + 1) * sizeof(rct_research_item)); + + // Place new item + researchItem->entryIndex = entryIndex; + researchItem->category = category; + break; + } + } while (entryIndex != (researchItem++)->entryIndex); +} + +/** + * + * rct2: 0x00685826 + */ +static void research_insert_researched(int entryIndex, int category) +{ + rct_research_item *researchItem, *researchItem2; + + researchItem = gResearchItems; + do { + if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPERATOR) { + // Insert slot + researchItem2 = researchItem; + while (researchItem2->entryIndex != RESEARCHED_ITEMS_END_2) { + researchItem2++; + } + memmove(researchItem + 1, researchItem, (researchItem2 - researchItem + 1) * sizeof(rct_research_item)); + + // Place new item + researchItem->entryIndex = entryIndex; + researchItem->category = category; + break; + } + } while (entryIndex != (researchItem++)->entryIndex); +} + +void research_insert(int researched, int entryIndex, int category) +{ + if (researched) + research_insert_researched(entryIndex, category); + else + research_insert_unresearched(entryIndex, category); +} + +/** + * + * rct2: 0x00685675 + */ +void research_populate_list_random() +{ + rct_ride_type *rideEntry; + rct_scenery_set_entry *scenerySetEntry; + int rideType, researched; + + // Rides + for (int i = 0; i < 128; i++) { + rideEntry = GET_RIDE_ENTRY(i); + if (rideEntry == (rct_ride_type*)-1) + continue; + + researched = (scenario_rand() & 0xFF) > 128; + for (int j = 0; j < 3; j++) { + rideType = rideEntry->ride_type[j]; + if (rideType != 255) + research_insert(researched, 0x10000 | (rideType << 8) | i, rideEntry->category[0]); + } + } + + // Scenery + for (int i = 0; i < 19; i++) { + scenerySetEntry = g_scenerySetEntries[i]; + if (scenerySetEntry == (rct_scenery_set_entry*)-1) + continue; + + researched = (scenario_rand() & 0xFF) > 85; + research_insert(researched, i, RESEARCH_CATEGORY_SCENERYSET); + } +} + +void research_populate_list_researched() +{ + rct_ride_type *rideEntry; + rct_scenery_set_entry *scenerySetEntry; + int rideType; + + // Rides + for (int i = 0; i < 128; i++) { + rideEntry = GET_RIDE_ENTRY(i); + if (rideEntry == (rct_ride_type*)-1) + continue; + + for (int j = 0; j < 3; j++) { + rideType = rideEntry->ride_type[j]; + if (rideType != 255) + research_insert(true, 0x10000 | (rideType << 8) | i, rideEntry->category[0]); + } + } + + // Scenery + for (int i = 0; i < 19; i++) { + scenerySetEntry = g_scenerySetEntries[i]; + if (scenerySetEntry == (rct_scenery_set_entry*)-1) + continue; + + research_insert(true, i, RESEARCH_CATEGORY_SCENERYSET); + } +} + +void research_set_funding(int amount) +{ + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, amount, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0); + +} + +void research_set_priority(int activeCategories) +{ + game_do_command(0, (1 << 8) | GAME_COMMAND_FLAG_APPLY, 0, activeCategories, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0); +} + +/** + * + * rct2: 0x00684A7F + */ +void game_command_set_research_funding(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + int setPriorities = (*ebx & (1 << 8)) != 0; + int fundingAmount = *edx; + int activeCategories = *edx; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RESEARCH * 4; + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + if (!setPriorities) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8) = fundingAmount; + else + RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint8) = activeCategories; + + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_RESEARCH); + } + + *ebx = 0; } \ No newline at end of file diff --git a/src/management/research.h b/src/management/research.h index f2789fd151..e26725b6db 100644 --- a/src/management/research.h +++ b/src/management/research.h @@ -29,8 +29,17 @@ typedef struct { uint8 category; } rct_research_item; +enum{ + RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED = (1 << 29), + RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED = (1 << 30), +}; + +// Everything before this point has been researched #define RESEARCHED_ITEMS_SEPERATOR -1 +// Everything before this point and after seperator still requires research #define RESEARCHED_ITEMS_END -2 +// Extra end of list entry. Unsure why? +#define RESEARCHED_ITEMS_END_2 -3 enum { RESEARCH_FUNDING_NONE, @@ -43,15 +52,36 @@ enum { RESEARCH_STAGE_INITIAL_RESEARCH, RESEARCH_STAGE_DESIGNING, RESEARCH_STAGE_COMPLETING_DESIGN, - RESEARCH_STAGE_UNKNOWN + RESEARCH_STAGE_UNKNOWN, + RESEARCH_STAGE_FINISHED_ALL +}; + +enum { + RESEARCH_CATEGORY_TRANSPORT, + RESEARCH_CATEGORY_GENTLE, + RESEARCH_CATEGORY_ROLLERCOASTER, + RESEARCH_CATEGORY_THRILL, + RESEARCH_CATEGORY_WATER, + RESEARCH_CATEGORY_SHOP, + RESEARCH_CATEGORY_SCENERYSET }; extern rct_research_item *gResearchItems; extern uint8 gResearchUncompletedCategories; +extern bool gSilentResearch; void research_reset_items(); void research_update_uncompleted_types(); void research_update(); void sub_684AC3(); +void research_remove_non_separate_vehicle_types(); +void research_populate_list_random(); +void research_populate_list_researched(); + +void research_set_funding(int amount); +void research_set_priority(int activeCategories); +void game_command_set_research_funding(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void research_finish_item(sint32 entryIndex); +void research_insert(int researched, int entryIndex, int category); #endif \ No newline at end of file diff --git a/src/network/http.cpp b/src/network/http.cpp new file mode 100644 index 0000000000..a2ad158bec --- /dev/null +++ b/src/network/http.cpp @@ -0,0 +1,149 @@ +extern "C" { + #include "http.h" +} + +#ifdef DISABLE_HTTP + +void http_init() { } +void http_dispose() { } + +#else + +#include +#include +#include + +typedef struct { + char *ptr; + int length; + int capacity; +} write_buffer; + +void http_init() +{ + curl_global_init(CURL_GLOBAL_DEFAULT); +} + +void http_dispose() +{ + curl_global_cleanup(); +} + +static size_t http_request_write_func(void *ptr, size_t size, size_t nmemb, void *userdata) +{ + write_buffer *writeBuffer = (write_buffer*)userdata; + + int newBytesLength = size * nmemb; + if (newBytesLength > 0) { + int newCapacity = writeBuffer->capacity; + int newLength = writeBuffer->length + newBytesLength; + while (newLength > newCapacity) { + newCapacity = max(4096, newCapacity * 2); + } + if (newCapacity != writeBuffer->capacity) { + writeBuffer->ptr = (char*)realloc(writeBuffer->ptr, newCapacity); + writeBuffer->capacity = newCapacity; + } + + memcpy(writeBuffer->ptr + writeBuffer->length, ptr, newBytesLength); + writeBuffer->length = newLength; + } + return newBytesLength; +} + +http_json_response *http_request_json(const char *url) +{ + CURL *curl; + CURLcode curlResult; + http_json_response *response; + write_buffer writeBuffer; + + curl = curl_easy_init(); + if (curl == NULL) + return NULL; + + writeBuffer.ptr = NULL; + writeBuffer.length = 0; + writeBuffer.capacity = 0; + + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE); + curl_easy_setopt(curl, CURLOPT_CAINFO, "curl-ca-bundle.crt"); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeBuffer); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_request_write_func); + + curlResult = curl_easy_perform(curl); + if (curlResult != CURLE_OK) { + log_error("HTTP request failed: %s.", curl_easy_strerror(curlResult)); + if (writeBuffer.ptr != NULL) + free(writeBuffer.ptr); + + return NULL; + } + + long httpStatusCode; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStatusCode); + + curl_easy_cleanup(curl); + + // Null terminate the response buffer + writeBuffer.length++; + writeBuffer.ptr = (char*)realloc(writeBuffer.ptr, writeBuffer.length); + writeBuffer.capacity = writeBuffer.length; + writeBuffer.ptr[writeBuffer.length - 1] = 0; + + response = NULL; + + // Parse as JSON + json_t *root; + json_error_t error; + root = json_loads(writeBuffer.ptr, 0, &error); + if (root != NULL) { + response = (http_json_response*)malloc(sizeof(http_json_response)); + response->status_code = (int)httpStatusCode; + response->root = root; + } + free(writeBuffer.ptr); + return response; +} + +void http_request_json_async(const char *url, void (*callback)(http_json_response*)) +{ + struct TempThreadArgs { + char *url; + void (*callback)(http_json_response*); + }; + + TempThreadArgs *args = (TempThreadArgs*)malloc(sizeof(TempThreadArgs)); + args->url = _strdup(url); + args->callback = callback; + + SDL_Thread *thread = SDL_CreateThread([](void *ptr) -> int { + TempThreadArgs *args = (TempThreadArgs*)ptr; + + http_json_response *response = http_request_json(args->url); + args->callback(response); + + free(args->url); + free(args); + return 0; + }, NULL, args); + + if (thread == NULL) { + log_error("Unable to create thread!"); + callback(NULL); + } else { + SDL_DetachThread(thread); + } +} + +void http_request_json_dispose(http_json_response *response) +{ + if (response->root != NULL) + json_decref(response->root); + + free(response); +} + +#endif \ No newline at end of file diff --git a/src/network/http.h b/src/network/http.h new file mode 100644 index 0000000000..ffc051a235 --- /dev/null +++ b/src/network/http.h @@ -0,0 +1,18 @@ +#ifndef _HTTP_H_ +#define _HTTP_H_ + +#include +#include "../common.h" + +typedef struct { + int status_code; + json_t *root; +} http_json_response; + +void http_init(); +void http_dispose(); +http_json_response *http_request_json(const char *url); +void http_request_json_async(const char *url, void (*callback)(http_json_response*)); +void http_request_json_dispose(http_json_response *response); + +#endif diff --git a/src/network/twitch.cpp b/src/network/twitch.cpp new file mode 100644 index 0000000000..1e36c0526b --- /dev/null +++ b/src/network/twitch.cpp @@ -0,0 +1,435 @@ +#ifdef DISABLE_TWITCH + + extern "C" { + #include "twitch.h" + } + + void twitch_update() { } + +#else + +// REQUIRES HTTP + +#include +#include + +extern "C" { + + #include "../addresses.h" + #include "../config.h" + #include "../interface/console.h" + #include "../localisation/localisation.h" + #include "../management/news_item.h" + #include "../peep/peep.h" + #include "../world/sprite.h" + #include "http.h" + #include "twitch.h" + +} + +enum { + TWITCH_STATE_JOINING, + TWITCH_STATE_JOINED, + TWITCH_STATE_WAITING, + TWITCH_STATE_GET_FOLLOWERS, + TWITCH_STATE_GET_MESSAGES, + TWITCH_STATE_LEAVING, + TWITCH_STATE_LEFT +}; + +// The time between HTTP requests. +// TODO Ideally, the chat message pulse should be more frequent than the followers / chat members so that news messages etc. +// have a lower latency. +#define PULSE_TIME (10 * 1000) + +const char *TwitchExtendedBaseUrl = "http://openrct.ursalabs.co/api/1/"; + +bool gTwitchEnable = false; + +static int _twitchState = TWITCH_STATE_LEFT; +static bool _twitchIdle = true; +static uint32 _twitchLastPulseTick = 0; +static int _twitchLastPulseOperation = 1; +static http_json_response *_twitchJsonResponse; + +static void twitch_join(); +static void twitch_leave(); +static void twitch_get_followers(); +static void twitch_get_messages(); + +static void twitch_parse_followers(); +static void twitch_parse_messages(); +static void twitch_parse_chat_message(const char *message); + +void twitch_update() +{ + if (!_twitchIdle) + return; + + bool twitchable = + !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (~SCREEN_FLAGS_PLAYING)) && + gConfigTwitch.channel != NULL && + gConfigTwitch.channel[0] != 0 && + gTwitchEnable; + + if (twitchable) { + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) + return; + + switch (_twitchState) { + case TWITCH_STATE_LEFT: + { + uint32 currentTime = SDL_GetTicks(); + uint32 timeSinceLastPulse = currentTime - _twitchLastPulseTick; + if (_twitchLastPulseTick == 0 || timeSinceLastPulse > PULSE_TIME) { + _twitchLastPulseTick = currentTime; + twitch_join(); + } + break; + } + case TWITCH_STATE_JOINED: + { + uint32 currentTime = SDL_GetTicks(); + uint32 timeSinceLastPulse = currentTime - _twitchLastPulseTick; + if (_twitchLastPulseTick == 0 || timeSinceLastPulse > PULSE_TIME) { + _twitchLastPulseTick = currentTime; + _twitchLastPulseOperation = (_twitchLastPulseOperation + 1) % 2; + switch (_twitchLastPulseOperation + TWITCH_STATE_GET_FOLLOWERS) { + case TWITCH_STATE_GET_FOLLOWERS: + twitch_get_followers(); + break; + case TWITCH_STATE_GET_MESSAGES: + if (gConfigTwitch.enable_news) + twitch_get_messages(); + break; + } + } + break; + } + case TWITCH_STATE_GET_FOLLOWERS: + twitch_parse_followers(); + break; + case TWITCH_STATE_GET_MESSAGES: + twitch_parse_messages(); + break; + } + } else { + if (_twitchState != TWITCH_STATE_LEFT) + twitch_leave(); + } +} + +/** + * GET /leave/:join + */ +static void twitch_join() +{ + char url[256]; + sprintf(url, "%sjoin/%s", TwitchExtendedBaseUrl, gConfigTwitch.channel); + + _twitchState = TWITCH_STATE_JOINING; + _twitchIdle = false; + http_request_json_async(url, [](http_json_response *jsonResponse) -> void { + if (jsonResponse == NULL) { + _twitchState = TWITCH_STATE_LEFT; + console_writeline("Unable to connect to twitch channel."); + } else { + json_t *jsonStatus = json_object_get(jsonResponse->root, "status"); + if (json_is_number(jsonStatus) && json_integer_value(jsonStatus) == 200) + _twitchState = TWITCH_STATE_JOINED; + else + _twitchState = TWITCH_STATE_LEFT; + + http_request_json_dispose(jsonResponse); + + _twitchLastPulseTick = 0; + console_writeline("Connected to twitch channel."); + } + _twitchIdle = true; + }); +} + +/** + * GET /leave/:channel + */ +static void twitch_leave() +{ + if (_twitchJsonResponse != NULL) { + http_request_json_dispose(_twitchJsonResponse); + _twitchJsonResponse = NULL; + } + + console_writeline("Left twitch channel."); + _twitchState = TWITCH_STATE_LEFT; + _twitchLastPulseTick = 0; + gTwitchEnable = false; + + // TODO reset all peeps with twitch flag + + // HTTP request no longer used as it could be abused + // char url[256]; + // sprintf(url, "%sleave/%s", TwitchExtendedBaseUrl, gConfigTwitch.channel); + // _twitchState = TWITCH_STATE_LEAVING; + // _twitchIdle = false; + // http_request_json_async(url, [](http_json_response *jsonResponse) -> void { + // http_request_json_dispose(jsonResponse); + // _twitchState = TWITCH_STATE_LEFT; + // _twitchIdle = true; + // + // console_writeline("Left twitch channel."); + // }); +} + +/** + * GET /channel/:channel/audience + */ +static void twitch_get_followers() +{ + char url[256]; + sprintf(url, "%schannel/%s/audience", TwitchExtendedBaseUrl, gConfigTwitch.channel); + + _twitchState = TWITCH_STATE_WAITING; + _twitchIdle = false; + http_request_json_async(url, [](http_json_response *jsonResponse) -> void { + if (jsonResponse == NULL) { + _twitchState = TWITCH_STATE_JOINED; + } else { + _twitchJsonResponse = jsonResponse; + _twitchState = TWITCH_STATE_GET_FOLLOWERS; + } + _twitchIdle = true; + }); +} + +/** + * GET /channel/:channel/messages + */ +static void twitch_get_messages() +{ + char url[256]; + sprintf(url, "%schannel/%s/messages", TwitchExtendedBaseUrl, gConfigTwitch.channel); + + _twitchState = TWITCH_STATE_WAITING; + _twitchIdle = false; + http_request_json_async(url, [](http_json_response *jsonResponse) -> void { + if (jsonResponse == NULL) { + _twitchState = TWITCH_STATE_JOINED; + } else { + _twitchJsonResponse = jsonResponse; + _twitchState = TWITCH_STATE_GET_MESSAGES; + } + _twitchIdle = true; + }); +} + +static void twitch_parse_followers() +{ + struct AudienceMember { + const char *name; + bool isFollower; + bool isInChat; + bool isMod; + bool exists; + bool shouldTrack; + }; + + std::vector members; + + http_json_response *jsonResponse = _twitchJsonResponse; + if (json_is_array(jsonResponse->root)) { + int audienceCount = json_array_size(jsonResponse->root); + for (int i = 0; i < audienceCount; i++) { + json_t *audienceMember = json_array_get(jsonResponse->root, i); + if (!json_is_object(audienceMember)) + continue; + + json_t *name = json_object_get(audienceMember, "name"); + json_t *isFollower = json_object_get(audienceMember, "isFollower"); + json_t *isInChat = json_object_get(audienceMember, "inChat"); + json_t *isMod = json_object_get(audienceMember, "isMod"); + + AudienceMember member; + member.name = json_string_value(name); + member.isFollower = json_boolean_value(isFollower); + member.isInChat = json_boolean_value(isInChat); + member.isMod = json_boolean_value(isMod); + member.exists = false; + member.shouldTrack = false; + + if (member.name == NULL || member.name[0] == 0) + continue; + + if (member.isInChat && gConfigTwitch.enable_chat_peep_tracking) + member.shouldTrack = true; + else if (member.isFollower && gConfigTwitch.enable_follower_peep_tracking) + member.shouldTrack = true; + + if (gConfigTwitch.enable_chat_peep_names && member.isInChat) + members.push_back(member); + else if (gConfigTwitch.enable_follower_peep_names && member.isFollower) + members.push_back(member); + } + + uint16 spriteIndex; + rct_peep *peep; + char buffer[256]; + + // Check what followers are already in the park + FOR_ALL_GUESTS(spriteIndex, peep) { + if (is_user_string_id(peep->name_string_idx)) { + format_string(buffer, peep->name_string_idx, NULL); + + AudienceMember *member = NULL; + for (size_t i = 0; i < members.size(); i++) { + if (_strcmpi(buffer, members[i].name) == 0) { + member = &members[i]; + members[i].exists = true; + break; + } + } + + if (peep->flags & PEEP_FLAGS_TWITCH) { + if (member == NULL) { + // Member no longer peep name worthy + peep->flags &= ~(PEEP_FLAGS_TRACKING | PEEP_FLAGS_TWITCH); + + // TODO set peep name back to number / real name + } else { + if (member->shouldTrack) + peep->flags |= (PEEP_FLAGS_TRACKING); + else if (!member->shouldTrack) + peep->flags &= ~(PEEP_FLAGS_TRACKING); + } + } else if (member != NULL && !(peep->flags & PEEP_FLAGS_LEAVING_PARK)) { + // Peep with same name already exists but not twitch + peep->flags |= PEEP_FLAGS_TWITCH; + if (member->shouldTrack) + peep->flags |= PEEP_FLAGS_TRACKING; + } + } + } + + // Rename non-named peeps to followers that aren't currently in the park. + if (members.size() > 0) { + int memberIndex = -1; + FOR_ALL_GUESTS(spriteIndex, peep) { + int originalMemberIndex = memberIndex; + for (size_t i = memberIndex + 1; i < members.size(); i++) { + if (!members[i].exists) { + memberIndex = i; + break; + } + } + if (originalMemberIndex == memberIndex) + break; + + AudienceMember *member = &members[memberIndex]; + if (!is_user_string_id(peep->name_string_idx) && !(peep->flags & PEEP_FLAGS_LEAVING_PARK)) { + // Rename peep and add flags + rct_string_id newStringId = user_string_allocate(4, member->name); + if (newStringId != 0) { + peep->name_string_idx = newStringId; + peep->flags |= PEEP_FLAGS_TWITCH; + if (member->shouldTrack) + peep->flags |= PEEP_FLAGS_TRACKING; + } + } else { + // Peep still yet to be found for member + memberIndex--; + } + } + } + } + + http_request_json_dispose(_twitchJsonResponse); + _twitchJsonResponse = NULL; + _twitchState = TWITCH_STATE_JOINED; + + gfx_invalidate_screen(); +} + +static void twitch_parse_messages() +{ + http_json_response *jsonResponse = _twitchJsonResponse; + if (json_is_array(jsonResponse->root)) { + int messageCount = json_array_size(jsonResponse->root); + for (int i = 0; i < messageCount; i++) { + json_t *jsonMessage = json_array_get(jsonResponse->root, i); + if (!json_is_object(jsonMessage)) + continue; + + json_t *jsonText = json_object_get(jsonMessage, "message"); + const char *text = json_string_value(jsonText); + + twitch_parse_chat_message(text); + } + } + + http_request_json_dispose(_twitchJsonResponse); + _twitchJsonResponse = NULL; + _twitchState = TWITCH_STATE_JOINED; +} + +/** + * Like strchr but allows searching for one of many characters. + */ +static char *strchrm(const char *str, const char *find) +{ + const char *result = NULL; + do { + const char *fch = find; + while (*fch != 0) { + if (*str == *fch) + return (char*)str; + + fch++; + } + } while (*str++ != 0); + return NULL; +} + +static char *strskipwhitespace(const char *str) +{ + while (*str == ' ' || *str == '\t') + str++; + + return (char*)str; +} + +static void twitch_parse_chat_message(const char *message) +{ + char buffer[256], *ch; + + message = strskipwhitespace(message); + if (message[0] != '!') + return; + + message++; + ch = strchrm(message, " \t"); + strncpy(buffer, message, ch - message); + buffer[ch - message] = 0; + if (_strcmpi(buffer, "news") == 0) { + if (gConfigTwitch.enable_news) { + ch = strskipwhitespace(ch); + + buffer[0] = (char)FORMAT_TOPAZ; + strncpy(buffer + 1, ch, sizeof(buffer) - 2); + buffer[sizeof(buffer) - 2] = 0; + + // Remove unsupport characters + // TODO allow when OpenRCT2 gains unicode support + ch = buffer; + while (ch[0] != 0) { + if ((unsigned char)ch[0] < 32 || (unsigned char)ch[0] > 122) { + ch[0] = ' '; + } + ch++; + } + + // TODO Create a new news item type for twitch which has twitch icon + news_item_add_to_queue_raw(NEWS_ITEM_BLANK, buffer, 0); + } + } +} + +#endif \ No newline at end of file diff --git a/src/network/twitch.h b/src/network/twitch.h new file mode 100644 index 0000000000..247c721281 --- /dev/null +++ b/src/network/twitch.h @@ -0,0 +1,10 @@ +#ifndef _TWITCH_H_ +#define _TWITCH_H_ + +#include "../common.h" + +extern bool gTwitchEnable; + +void twitch_update(); + +#endif \ No newline at end of file diff --git a/src/object.c b/src/object.c index 03ce1d7d80..0f83bab287 100644 --- a/src/object.c +++ b/src/object.c @@ -8,12 +8,12 @@ * 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 . *****************************************************************************/ @@ -21,14 +21,20 @@ #include "addresses.h" #include "localisation/localisation.h" #include "object.h" -#include "platform/osinterface.h" #include "platform/platform.h" +#include "ride/ride.h" #include "util/sawyercoding.h" +#include "drawing/drawing.h" +#include "world/footpath.h" +#include "world/water.h" +#include "world/entrance.h" +#include "world/scenery.h" +#include "scenario.h" int object_load_entry(const char *path, rct_object_entry *outEntry) { FILE *file; - + file = fopen(path, "rb"); if (file == NULL) return 0; @@ -51,7 +57,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), (char*)installedObject + 16); - // log_verbose("loading object, %s", path); + log_verbose("loading object, %s", path); file = fopen(path, "rb"); if (file == NULL) @@ -71,7 +77,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi // Read chunk size *chunkSize = *((uint32*)installedObject_pointer); char *chunk; - + if (*chunkSize == 0xFFFFFFFF) { chunk = rct2_malloc(0x600000); *chunkSize = sawyercoding_read_chunk(file, chunk); @@ -83,7 +89,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi } fclose(file); - + // Calculate and check checksum if (object_calculate_checksum(&openedEntry, chunk, *chunkSize) != openedEntry.checksum) { @@ -102,15 +108,13 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi return 0; } - int yyy = RCT2_GLOBAL(0x009ADAF0, uint32); - - if (yyy >= 0x4726E){ - log_error("Object Load failed due to yyy failure."); + if (RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) >= 0x4726E){ + log_error("Object Load failed due to too many images loaded."); RCT2_GLOBAL(0x00F42BD9, uint8) = 4; rct2_free(chunk); return 0; } - + uint8** chunk_list = object_entry_groups[objectType].chunks; if (groupIndex == -1) { for (groupIndex = 0; chunk_list[groupIndex] != (uint8*)-1; groupIndex++) { @@ -137,7 +141,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi } /** - * + * * rct2: 0x006A985D */ int object_load(int groupIndex, rct_object_entry *entry, int* chunkSize) @@ -167,32 +171,34 @@ int object_load(int groupIndex, rct_object_entry *entry, int* chunkSize) return 0; } -/** rct2: 0x006a9f42 +/** rct2: 0x006a9f42 * ebx : file * ebp : entry */ -int sub_6A9F42(FILE *file, rct_object_entry* entry){ - int eax = 0, entryGroupIndex = 0, type = 0, edx = 0, edi = 0, ebp = (int)entry, chunk = 0; - RCT2_CALLFUNC_X(0x6A9DA2, &eax, &entryGroupIndex, &type, &edx, &chunk, &edi, &ebp); - if (eax == 0) return 0; +int write_object_file(FILE *file, rct_object_entry* entry){ + uint8 entryGroupIndex = 0, type = 0; + uint8* chunk = 0; - object_paint(type, 1, entryGroupIndex, type, edx, chunk, edi, ebp); - + if (!find_object_in_entry_group(entry, &type, &entryGroupIndex))return 0; + + chunk = object_entry_groups[type].chunks[entryGroupIndex]; + + object_paint(type, 1, entryGroupIndex, type, 0, (int)chunk, 0, 0); rct_object_entry_extended* installed_entry = &object_entry_groups[type].entries[entryGroupIndex]; uint8* dst_buffer = malloc(0x600000); - memcpy(dst_buffer, (uint8*)installed_entry, sizeof(rct_object_entry)); + memcpy(dst_buffer, installed_entry, sizeof(rct_object_entry)); uint32 size_dst = sizeof(rct_object_entry); - sawyercoding_chunk_header chunkHeader; + sawyercoding_chunk_header chunkHeader; // Encoding type (not used anymore) RCT2_GLOBAL(0x9E3CBD, uint8) = object_entry_group_encoding[type]; chunkHeader.encoding = object_entry_group_encoding[type]; chunkHeader.length = installed_entry->chunk_size; - size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry), (uint8*)chunk, chunkHeader); + size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry), chunk, chunkHeader); fwrite(dst_buffer, 1, size_dst, file); free(dst_buffer); @@ -207,37 +213,39 @@ int object_load_packed(FILE *file) { object_unload_all(); - rct_object_entry* entry = RCT2_ADDRESS(0xF42B84, rct_object_entry); + rct_object_entry entry; - fread((void*)entry, 16, 1, file); + fread(&entry, 16, 1, file); uint8* chunk = rct2_malloc(0x600000); uint32 chunkSize = sawyercoding_read_chunk(file, chunk); chunk = rct2_realloc(chunk, chunkSize); + if (chunk == NULL){ + log_error("Failed to allocate memory for packed object."); return 0; } - if (object_calculate_checksum(entry, chunk, chunkSize) != entry->checksum){ + if (object_calculate_checksum(&entry, chunk, chunkSize) != entry.checksum){ + log_error("Checksum missmatch from packed object: %.8s", entry.name); rct2_free(chunk); return 0; } - if (object_paint(entry->flags & 0x0F, 2, 0, entry->flags & 0x0F, 0, (int)chunk, 0, 0)) { + int type = entry.flags & 0x0F; + + if (object_paint(type, 2, 0, type, 0, (int)chunk, 0, 0)) { + log_error("Packed object failed paint test."); rct2_free(chunk); return 0; } - int yyy = RCT2_GLOBAL(0x009ADAF0, uint32); - - if (yyy >= 0x4726E){ + if (RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) >= 0x4726E){ + log_error("Packed object has too many images."); rct2_free(chunk); return 0; } - int type = entry->flags & 0x0F; - - // ecx int entryGroupIndex = 0; for (; entryGroupIndex < object_entry_group_counts[type]; entryGroupIndex++){ @@ -247,21 +255,24 @@ int object_load_packed(FILE *file) } if (entryGroupIndex == object_entry_group_counts[type]){ + // This should never occur. Objects are not loaded before installing a + // packed object. So there is only one object loaded at this point. + log_error("Too many objects of the same type loaded."); rct2_free(chunk); return 0; } + // Copy the entry into the relevant entry group. object_entry_groups[type].chunks[entryGroupIndex] = chunk; - rct_object_entry_extended* edx = &object_entry_groups[type].entries[entryGroupIndex]; - memcpy(edx, (int*)entry, sizeof(rct_object_entry)); - edx->chunk_size = chunkSize; + rct_object_entry_extended* extended_entry = &object_entry_groups[type].entries[entryGroupIndex]; + memcpy(extended_entry, &entry, sizeof(rct_object_entry)); + extended_entry->chunk_size = chunkSize; - //esi + // Ensure the entry does not already exist. rct_object_entry *installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); - if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)){ for (uint32 i = 0; i < RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); ++i){ - if (object_entry_compare(entry, installedObject)){ + if (object_entry_compare(&entry, installedObject)){ object_unload_all(); return 0; } @@ -269,24 +280,23 @@ int object_load_packed(FILE *file) } } - //Installing new data - //format_string(0x141ED68, 3163, 0); - //Code for updating progress bar removed. - + // Convert the entry name to a upper case path name char path[260]; - char objectPath[13] = { 0 }; + char objectPath[9] = { 0 }; for (int i = 0; i < 8; ++i){ - if (entry->name[i] != ' ') - objectPath[i] = toupper(entry->name[i]); + if (entry.name[i] != ' ') + objectPath[i] = toupper(entry.name[i]); else objectPath[i] = '\0'; } subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath); + // Require pointer to start of filename char* last_char = path + strlen(path); strcat(path, ".DAT"); - // + // Check that file does not exist + // Adjust filename if it does. for (; platform_file_exists(path);){ for (char* curr_char = last_char - 1;; --curr_char){ if (*curr_char == '\\'){ @@ -302,34 +312,23 @@ int object_load_packed(FILE *file) } } - // Removed progress bar code - - // The following section cannot be finished until 6A9F42 is finished - // Run the game once with vanila rct2 to not reach this part of code. - log_verbose("Function might not be finished."); + // Actually write the object to the file FILE* obj_file = fopen(path, "wb"); if (obj_file){ - // Removed progress bar code - sub_6A9F42(obj_file, entry); + uint8 result = write_object_file(obj_file, &entry); + fclose(obj_file); - // Removed progress bar code object_unload_all(); - // Removed progress bar code - return 1; + + return result; } - else{ - object_unload_all(); - return 0; - } - //create file - //6aa48C - int eax = 1;//, ebx = 0, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = 0; - //RCT2_CALLFUNC_X(0x006AA2B7, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return 1; + + object_unload_all(); + return 0; } /** - * + * * rct2: 0x006A9CAF */ void object_unload(int groupIndex, rct_object_entry_extended *entry) @@ -339,6 +338,7 @@ void object_unload(int groupIndex, rct_object_entry_extended *entry) int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b) { + // If an official object don't bother checking checksum if (a->flags & 0xF0) { if ((a->flags & 0x0F) != (b->flags & 0x0F)) return 0; @@ -346,7 +346,8 @@ int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b) return 0; if (*((uint32*)(&a->name[4])) != *((uint32*)(&b->name[4]))) return 0; - } else { + } + else { if (a->flags != b->flags) return 0; if (*((uint32*)a->name) != *((uint32*)b->name)) @@ -381,122 +382,1216 @@ int object_calculate_checksum(const rct_object_entry *entry, const char *data, i return checksum; } -/** - * rct2: 0x66B355 part - * If al is 0 - * chunk : esi - */ -int object_scenario_load_custom_text(char* chunk){ - int ebp = (int)(&((uint32*)chunk)[2]); - int edx = 0; - int eax, ebx, ecx, edi; - RCT2_CALLFUNC_X(0x6A9E24, &eax, &ebx, &ecx, &edx, (int*)&chunk, &edi, &ebp); - *((uint16*)chunk) = eax; - edx++; - RCT2_CALLFUNC_X(0x6A9E24, &eax, &ebx, &ecx, &edx, (int*)&chunk, &edi, &ebp); - *((uint16*)chunk + 1) = eax; - edx++; - RCT2_CALLFUNC_X(0x6A9E24, &eax, &ebx, &ecx, &edx, (int*)&chunk, &edi, &ebp); - *((uint16*)chunk + 2) = eax; +/* rct2: 0x006A9ED1 */ +int object_chunk_load_image_directory(uint8_t** chunk) +{ + int image_start_no = RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32_t); + + // First dword of chunk is no_images + int no_images = *((uint32_t*)(*chunk)); + *chunk += 4; + // Second dword of chunk is length of image data + int length_of_data = *((uint32_t*)(*chunk)); + *chunk += 4; - if (RCT2_GLOBAL(0x9ADAF4, int) == -1)return 0; - else *(RCT2_GLOBAL(0x9ADAF4, uint32*)) = 0; - return 1; + RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32_t) = no_images + image_start_no; + + rct_g1_element* g1_dest = &g1Elements[image_start_no]; + + // After length of data is the start of all g1 element structs + rct_g1_element* g1_source = (rct_g1_element*)(*chunk); + + // After the g1 element structs is the actual images. + uint8* image_offset = no_images * sizeof(rct_g1_element) + (uint8*)g1_source; + + for (int i = 0; i < no_images; ++i){ + *g1_dest = *g1_source++; + g1_dest->offset += (uint32)image_offset; + g1_dest++; + } + + *chunk = ((uint8*)g1_source) + length_of_data; + return image_start_no; +} + +/* rct2: 0x006DE83E */ +int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // esi + rct_ride_type* ride_type = (rct_ride_type*)esi; + + // After ride_type is 3 string tables + uint8_t* chunk = (uint8*)(ride_type + 1); + ride_type->name = object_get_localised_text(&chunk, ecx, ebx, 0); + ride_type->description = object_get_localised_text(&chunk, ecx, ebx, 1); + object_get_localised_text(&chunk, ecx, ebx, 2); + // Offset to Unknown struct + ride_type->var_1AE = (uint32_t)chunk; + + // If Unknown struct size is 0xFF then there are 32 3 byte structures + uint8 unknown_size = *chunk++; + if (unknown_size != 0xFF) + { + chunk += unknown_size * 3; + } + else { + chunk += 0x60; + } + + sint8* peep_loading_positions = chunk; + // Peep loading positions variable size + // 4 different vehicle subtypes are available + for (int i = 0; i < 4; ++i){ + uint16 no_peep_positions = *chunk++; + // If no_peep_positions is 0xFF then no_peep_positions is a word + if (no_peep_positions == 0xFF) + { + no_peep_positions = *((uint16_t*)chunk); + chunk += 2; + } + chunk += no_peep_positions; + } + + int images_offset = object_chunk_load_image_directory(&chunk); + ride_type->images_offset = images_offset; + + int cur_vehicle_images_offset = images_offset + 3; + + for (int i = 0; i < 4; ++i){ + rct_ride_type_vehicle* rideVehicleEntry = &ride_type->vehicles[i]; + + if (rideVehicleEntry->var_0C & 1){ + int al = 1; + if (rideVehicleEntry->var_14 & 2) + { + al = 13; + if ((rideVehicleEntry->var_14 & 0x820) != 0x820) + { + al = 7; + if (!(rideVehicleEntry->var_14 & 0x20)) + { + if (!(rideVehicleEntry->var_14 & 0x800)) + { + al = 5; + if (rideVehicleEntry->var_14 & 0x200) al = 3; + } + } + } + } + rideVehicleEntry->var_03 = al; + // 0x6DE90B + + al = 0x20; + if (!(rideVehicleEntry->var_12 & 0x4000)) + { + al = 1; + if (rideVehicleEntry->var_14 & 0x80) + { + if (rideVehicleEntry->var_11 != 6) + { + al = 2; + if (!(rideVehicleEntry->var_12 & 0x80)) al = 4; + } + } + } + if (rideVehicleEntry->var_12 & 0x1000) al = rideVehicleEntry->var_60; + rideVehicleEntry->var_02 = al; + // 0x6DE946 + + rideVehicleEntry->var_16 = rideVehicleEntry->var_02 * rideVehicleEntry->var_03; + rideVehicleEntry->base_image_id = cur_vehicle_images_offset; + int image_index = rideVehicleEntry->base_image_id; + + if (rideVehicleEntry->var_5D != 4){ + int b = rideVehicleEntry->var_16 * 32; + + if (rideVehicleEntry->var_12 & 0x800) b /= 2; + if (rideVehicleEntry->var_0C & 0x8000) b /= 8; + + image_index += b; + + // Incline 25 + if (rideVehicleEntry->var_0C & 0x2){ + rideVehicleEntry->var_20 = image_index; + b = rideVehicleEntry->var_16 * 72; + if (rideVehicleEntry->var_12 & 0x4000) + b = rideVehicleEntry->var_16 * 16; + + image_index += b; + } + + // Incline 60 + if (rideVehicleEntry->var_0C & 0x4){ + rideVehicleEntry->var_24 = image_index; + b = rideVehicleEntry->var_16 * 80; + image_index += b; + } + // Verticle + if (rideVehicleEntry->var_0C & 0x8){ + rideVehicleEntry->var_28 = image_index; + b = rideVehicleEntry->var_16 * 116; + image_index += b; + } + // Unknown + if (rideVehicleEntry->var_0C & 0x10){ + rideVehicleEntry->var_2C = image_index; + b = rideVehicleEntry->var_16 * 24; + image_index += b; + } + + // Bank + if (rideVehicleEntry->var_0C & 0x20){ + rideVehicleEntry->var_30 = image_index; + b = rideVehicleEntry->var_16 * 80; + image_index += b; + } + + if (rideVehicleEntry->var_0C & 0x40){ + rideVehicleEntry->var_34 = image_index; + b = rideVehicleEntry->var_16 * 40; + image_index += b; + } + + // Track half? Up/Down + if (rideVehicleEntry->var_0C & 0x80){ + rideVehicleEntry->var_38 = image_index; + b = rideVehicleEntry->var_16 * 128; + image_index += b; + } + // Unknown + if (rideVehicleEntry->var_0C & 0x100){ + rideVehicleEntry->var_3C = image_index; + b = rideVehicleEntry->var_16 * 16; + image_index += b; + } + // Unknown + if (rideVehicleEntry->var_0C & 0x200){ + rideVehicleEntry->var_40 = image_index; + b = rideVehicleEntry->var_16 * 16; + image_index += b; + } + + if (rideVehicleEntry->var_0C & 0x400){ + rideVehicleEntry->var_44 = image_index; + b = rideVehicleEntry->var_16 * 128; + image_index += b; + } + + if (rideVehicleEntry->var_0C & 0x800){ + rideVehicleEntry->var_48 = image_index; + b = rideVehicleEntry->var_16 * 16; + image_index += b; + } + + if (rideVehicleEntry->var_0C & 0x1000){ + rideVehicleEntry->var_4C = image_index; + b = rideVehicleEntry->var_16 * 80; + image_index += b; + } + // Unknown + if (rideVehicleEntry->var_0C & 0x2000){ + rideVehicleEntry->var_1C = image_index; + b = rideVehicleEntry->var_16 * 12; + image_index += b; + } + + if (rideVehicleEntry->var_0C & 0x4000){ + // Same offset as above??? + rideVehicleEntry->var_4C = image_index; + b = rideVehicleEntry->var_16 * 32; + image_index += b; + } + + } + else{ + image_index += rideVehicleEntry->var_16 * 36; + } + // No vehicle images + rideVehicleEntry->no_vehicle_images = image_index - cur_vehicle_images_offset; + + // Move the offset over this vehicles images. Including peeps + cur_vehicle_images_offset = image_index + rideVehicleEntry->no_seating_rows * rideVehicleEntry->no_vehicle_images; + // 0x6DEB0D + + if (!(rideVehicleEntry->var_12 & 0x400)){ + int ecx = cur_vehicle_images_offset - rideVehicleEntry->base_image_id; + if (rideVehicleEntry->var_12 & 0x2000){ + ecx *= 2; + } + + int bl, bh, eax = 0; + { + int ebx = rideVehicleEntry->base_image_id; + int edx = 0, esi = 0, ebp = 0, edi = 0; + RCT2_CALLFUNC_X(0x6847BA, &eax, &ebx, &ecx, &edx, &esi, &ebp, &edi); + bl = ebx & 0xFF; + bh = (ebx >> 8) & 0xFF; + } + + if (rideVehicleEntry->var_12 & 0x2000){ + bl += 16; + } + + rideVehicleEntry->var_0E = eax & 0xFF; + rideVehicleEntry->var_0F = bl; + rideVehicleEntry->var_10 = bh; + } + + uint8 no_positions = *peep_loading_positions++; + if (no_positions == 0xFF) + { + // The no_positions is 16 bit skip over + peep_loading_positions += 2; + } + rideVehicleEntry->peep_loading_positions = peep_loading_positions; + } + } + + // 0x6DEB71 + if (RCT2_GLOBAL(0x9ADAFD, uint8_t) == 0) + { + for (int i = 0; i < 3; ++i){ + int dl = ride_type->ride_type[i]; + + if (dl == 0xFF)continue; + + uint8 *typeToRideEntryIndexMap = RCT2_ADDRESS(0x009E32F8, uint8); + + while (dl >= 0){ + if (*typeToRideEntryIndexMap++ == 0xFF)dl--; + } + + typeToRideEntryIndexMap--; + uint8 previous_entry = ebx; + while (typeToRideEntryIndexMap < RCT2_ADDRESS(0x9E34E4, uint8)){ + uint8 backup_entry = *typeToRideEntryIndexMap; + *typeToRideEntryIndexMap++ = previous_entry; + previous_entry = backup_entry; + } + } + } + + // 0x6DEBAA + if (RCT2_GLOBAL(0x9ADAF4, sint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + + int di = ride_type->ride_type[0] | (ride_type->ride_type[1] << 8) | (ride_type->ride_type[2] << 16); + + if (ride_type->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME) di |= 0x1000000; + + RCT2_GLOBAL(0xF433DD, uint32) = di; + return 0;// flags; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_ride_type* ride_type = (rct_ride_type*)esi; + ride_type->name = 0; + ride_type->description = 0; + ride_type->images_offset = 0; + + for (int i = 0; i < 4; ++i){ + rct_ride_type_vehicle* rideVehicleEntry = &ride_type->vehicles[i]; + + rideVehicleEntry->base_image_id = 0; + rideVehicleEntry->var_1C = 0; + rideVehicleEntry->var_20 = 0; + rideVehicleEntry->var_24 = 0; + rideVehicleEntry->var_28 = 0; + rideVehicleEntry->var_2C = 0; + rideVehicleEntry->var_30 = 0; + rideVehicleEntry->var_34 = 0; + rideVehicleEntry->var_38 = 0; + rideVehicleEntry->var_3C = 0; + rideVehicleEntry->var_40 = 0; + rideVehicleEntry->var_44 = 0; + rideVehicleEntry->var_48 = 0; + rideVehicleEntry->var_4C = 0; + rideVehicleEntry->no_vehicle_images = 0; + rideVehicleEntry->var_16 = 0; + + if (!(rideVehicleEntry->var_12 & 0x400)){ + rideVehicleEntry->var_0E = 0; + rideVehicleEntry->var_0F = 0; + rideVehicleEntry->var_10 = 0; + } + rideVehicleEntry->var_02 = 0; + rideVehicleEntry->var_03 = 0; + rideVehicleEntry->peep_loading_positions = 0; + } + + ride_type->var_1AE = 0; + return flags; + } + else if ((flags & 0xFF) == 2){ + + rct_ride_type* ride_type = (rct_ride_type*)esi; + + if (ride_type->excitement_multipler > 75) return 1; + if (ride_type->intensity_multipler > 75) return 1; + if (ride_type->nausea_multipler > 75) return 1; + return 0; + } + else if ((flags & 0xFF) == 3){ + // Paint object picture and description + + rct_ride_type* ride_type = (rct_ride_type*)ebp; + int x = ecx, y = edx; + + if (!((flags >> 8) & 0xFF)) + { + int image_id = ride_type->images_offset; + if (ride_type->ride_type[0] == 0xFF) + { + image_id++; + if (ride_type->ride_type[1] == 0xFF) image_id++; + } + gfx_draw_sprite(dpi, image_id, x - 56, y - 56, ebp); + return flags; + } + else + { + rct_window* w = (rct_window*)esi; + int width = w->x + w->width - x - 4; + + int format_args = ride_type->description; + if (!(ride_type->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME)) + { + format_args = ride_type->ride_type[0]; + if ((format_args & 0xFF) == 0xFF) + { + format_args = ride_type->ride_type[1]; + if ((format_args & 0xFF) == 0xFF) format_args = ride_type->ride_type[2]; + } + format_args += 0x200; + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = format_args; + gfx_draw_string_left_wrapped(dpi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, x, y + 5, width, 1191, 0); + return flags; + } + } + + return flags; +} + +/* rct2: 0x006E3466 */ +int paint_small_scenery(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + uint8* chunk = (uint8*)(esi + 0x1C); + + scenery_type->name = object_get_localised_text(&chunk, ecx, ebx, 0); + + scenery_type->small_scenery.scenery_tab_id = 0xFF; + + if (*chunk != 0xFF){ + uint8 entry_type, entry_index; + if (find_object_in_entry_group((rct_object_entry*)chunk, &entry_type, &entry_index)){ + scenery_type->small_scenery.scenery_tab_id = entry_index; + } + } + + chunk += sizeof(rct_object_entry); + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG16){ + scenery_type->small_scenery.var_10 = (uint32)chunk; + while (*++chunk != 0xFF); + chunk++; + } + + scenery_type->image = object_chunk_load_image_directory(&chunk); + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + scenery_type->name = 0; + scenery_type->image = 0; + scenery_type->small_scenery.var_10 = 0; + scenery_type->small_scenery.scenery_tab_id = 0; + } + else if ((flags & 0xFF) == 2){ + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + + if (scenery_type->small_scenery.price <= 0)return 1; + + if (scenery_type->small_scenery.removal_price > 0) return 0; + + // Make sure you don't make a profit when placing then removing. + if (-scenery_type->small_scenery.removal_price > scenery_type->small_scenery.price)return 1; + + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + if (!((flags >> 8) & 0xFF)) + { + rct_scenery_entry* scenery_type = (rct_scenery_entry*)ebp; + + dpi = clip_drawpixelinfo(dpi, x - 56, 112, y - 56, 112); + if (dpi == NULL) return flags; + + int image_id = scenery_type->image; + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR){ + image_id |= 0x20D00000; + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + image_id |= 0x92000000; + } + + x = 56; + y = scenery_type->small_scenery.height / 4 + 78; + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE){ + y -= 12; + } + } + + gfx_draw_sprite(dpi, image_id, x, y, 0); + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG10){ + image_id = scenery_type->image + 0x44500004; + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + image_id |= 0x92000000; + + gfx_draw_sprite(dpi, image_id, x, y, 0); + } + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG8){ + image_id = scenery_type->image + 4; + + if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + image_id |= 0x92000000; + + gfx_draw_sprite(dpi, image_id, x, y, 0); + } + + rct2_free(dpi); + } + } + return flags; +} + +/* rct2: 0x006B92A7 */ +int paint_large_scenery(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + uint8* chunk = (uint8*)(esi + 0x1A); + + scenery_type->name = object_get_localised_text(&chunk, ecx, ebx, 0); + + scenery_type->large_scenery.scenery_tab_id = 0xFF; + + if (*chunk != 0xFF){ + uint8 entry_type, entry_index; + if (find_object_in_entry_group((rct_object_entry*)chunk, &entry_type, &entry_index)){ + scenery_type->large_scenery.scenery_tab_id = entry_index; + } + } + + chunk += sizeof(rct_object_entry); + + if (scenery_type->large_scenery.flags & (1<<2)){ + scenery_type->large_scenery.var_12 = (uint32)chunk; + chunk += 1038; + } + + scenery_type->large_scenery.tiles = (rct_large_scenery_tile*)chunk; + + // skip over large scenery tiles + while (*((uint16*)chunk) != 0xFFFF){ + chunk += sizeof(rct_large_scenery_tile); + } + + chunk += 2; + + int image_id = object_chunk_load_image_directory(&chunk); + if (scenery_type->large_scenery.flags & (1 << 2)){ + scenery_type->large_scenery.var_16 = image_id; + + uint8* edx = (uint8*)scenery_type->large_scenery.var_12; + if (!(edx[0xC] & 1)){ + image_id += edx[0xD] * 4; + } + else{ + image_id += edx[0xD] * 2; + } + } + scenery_type->image = image_id; + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + scenery_type->name = 0; + scenery_type->image = 0; + scenery_type->large_scenery.tiles = 0; + scenery_type->large_scenery.scenery_tab_id = 0; + scenery_type->large_scenery.var_12 = 0; + scenery_type->large_scenery.var_16 = 0; + } + else if ((flags & 0xFF) == 2){ + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + + if (scenery_type->large_scenery.price <= 0)return 1; + + if (scenery_type->large_scenery.removal_price > 0) return 0; + + // Make sure you don't make a profit when placing then removing. + if (-scenery_type->large_scenery.removal_price > scenery_type->large_scenery.price)return 1; + + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + if (!((flags >> 8) & 0xFF)) + { + rct_scenery_entry* scenery_type = (rct_scenery_entry*)ebp; + + int image_id = scenery_type->image | 0xB2D00000; + + gfx_draw_sprite(dpi, image_id, x, y - 39, 0); + } + } + return flags; +} + +/* rct2: 0x006E5A25 */ +int paint_wall(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + uint8* chunk = (uint8*)(esi + 0xE); + + scenery_type->name = object_get_localised_text(&chunk, ecx, ebx, 0); + + scenery_type->wall.scenery_tab_id = 0xFF; + + if (*chunk != 0xFF){ + uint8 entry_type, entry_index; + if (find_object_in_entry_group((rct_object_entry*)chunk, &entry_type, &entry_index)){ + scenery_type->wall.scenery_tab_id = entry_index; + } + } + + chunk += sizeof(rct_object_entry); + + scenery_type->image = object_chunk_load_image_directory(&chunk); + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + scenery_type->name = 0; + scenery_type->image = 0; + scenery_type->wall.scenery_tab_id = 0; + } + else if ((flags & 0xFF) == 2){ + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + + if (scenery_type->wall.price <= 0)return 1; + + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + + if (!((flags >> 8) & 0xFF)) + { + rct_scenery_entry* scenery_type = (rct_scenery_entry*)ebp; + + dpi = clip_drawpixelinfo(dpi, x - 56, 112, y - 56, 112); + if (dpi == NULL) return flags; + + int image_id = scenery_type->image; + + + image_id |= 0x20D00000; + + if (scenery_type->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) + image_id |= 0x92000000; + + + x = 70; + y = scenery_type->wall.height * 2 + 72; + + gfx_draw_sprite(dpi, image_id, x, y, 0); + + if (scenery_type->wall.flags & WALL_SCENERY_FLAG2){ + image_id = scenery_type->image + 0x44500006; + + gfx_draw_sprite(dpi, image_id, x, y, 0); + } + else if (scenery_type->wall.flags & WALL_SCENERY_FLAG5){ + image_id++; + + gfx_draw_sprite(dpi, image_id, x, y, 0); + } + rct2_free(dpi); + } + } + return flags; +} + +/* rct2: 0x006BA84E */ +int paint_banner(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + uint8* chunk = (uint8*)(esi + 0xC); + + scenery_type->name = object_get_localised_text(&chunk, ecx, ebx, 0); + + scenery_type->banner.scenery_tab_id = 0xFF; + + if (*chunk != 0xFF){ + uint8 entry_type, entry_index; + if (find_object_in_entry_group((rct_object_entry*)chunk, &entry_type, &entry_index)){ + scenery_type->banner.scenery_tab_id = entry_index; + } + } + + chunk += sizeof(rct_object_entry); + + scenery_type->image = object_chunk_load_image_directory(&chunk); + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + scenery_type->name = 0; + scenery_type->image = 0; + scenery_type->banner.scenery_tab_id = 0; + } + else if ((flags & 0xFF) == 2){ + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + if (scenery_type->banner.price <= 0)return 1; + + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + + if (!((flags >> 8) & 0xFF)) + { + rct_scenery_entry* scenery_type = (rct_scenery_entry*)ebp; + + int image_id = scenery_type->image; + + image_id |= 0x20D00000; + + + gfx_draw_sprite(dpi, image_id, x, y, 0); + + gfx_draw_sprite(dpi, image_id + 1, x, y, 0); + } + } + return flags; +} + +//rct2: 0x006A8621 +int paint_path_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_path_type* path_type = (rct_path_type*)esi; + // String table starts after path entry + // Note there are 2 spare bytes after + // the path entry. + uint8* chunk = (uint8*)(esi + 0xE); + + // Only 1 string table for paths + path_type->string_idx = object_get_localised_text(&chunk, ecx, ebx, 0); + + int image_id = object_chunk_load_image_directory(&chunk); + path_type->image = image_id; + path_type->bridge_image = image_id + 109; + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = 0; + // Set the default path for when opening footpath window + for (int i = 0; i < object_entry_group_counts[OBJECT_TYPE_PATHS]; ++i){ + rct_path_type* path_type_entry = (rct_path_type*)object_entry_groups[OBJECT_TYPE_PATHS].chunks[i]; + if ((uint32)path_type_entry == 0xFFFFFFFF) continue; + if (!(path_type_entry->flags & 4)) + { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = i; + break; + } + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = i; + + } + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_path_type* path_type = (rct_path_type*)esi; + path_type->string_idx = 0; + path_type->image = 0; + path_type->bridge_image = 0; + } + else if ((flags & 0xFF) == 2){ + + rct_path_type* path_type = (rct_path_type*)esi; + if (path_type->var_0A >= 2) return 1;//actually the carry bit should be set (stc) + else return 0; + } + else if ((flags & 0xFF) == 3){ + rct_path_type* path_type = (rct_path_type*)ebp; + if (!((flags >> 8) & 0xFF)) + { + //Draws preview for scenario editor! + gfx_draw_sprite(dpi, path_type->image + 71, ecx - 49, edx - 17, ebp); + gfx_draw_sprite(dpi, path_type->image + 72, ecx + 4, edx - 17, ebp); + } + + } + return flags; +} + +/* rct2: 0x006A86E2 */ +int paint_path_bit(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + uint8* chunk = (uint8*)(esi + 0xE); + + scenery_type->name = object_get_localised_text(&chunk, ecx, ebx, 0); + + scenery_type->path_bit.scenery_tab_id = 0xFF; + + if (*chunk != 0xFF){ + uint8 entry_type, entry_index; + if (find_object_in_entry_group((rct_object_entry*)chunk, &entry_type, &entry_index)){ + scenery_type->path_bit.scenery_tab_id = entry_index; + } + } + + chunk += sizeof(rct_object_entry); + + scenery_type->image = object_chunk_load_image_directory(&chunk); + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + scenery_type->name = 0; + scenery_type->image = 0; + scenery_type->path_bit.scenery_tab_id = 0; + } + else if ((flags & 0xFF) == 2){ + rct_scenery_entry* scenery_type = (rct_scenery_entry*)esi; + + if (scenery_type->path_bit.price <= 0)return 1; + + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + + if (!((flags >> 8) & 0xFF)) + { + rct_scenery_entry* scenery_type = (rct_scenery_entry*)ebp; + + int image_id = scenery_type->image; + + x -= 22; + y -= 24; + + gfx_draw_sprite(dpi, image_id, x, y, 0); + } + } + return flags; +} + +/* rct2: 0x006B93AA */ +int paint_scenery_set(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_scenery_set_entry* scenery_set = (rct_scenery_set_entry*)esi; + uint8* chunk = (uint8*)(esi + sizeof(rct_scenery_set_entry)); + + scenery_set->name = object_get_localised_text(&chunk, ecx, ebx, 0); + + rct_object_entry* entry_objects = NULL; + uint8* eax = RCT2_GLOBAL(0x9ADAF4, uint8*); + if ((uint32)eax != 0xFFFFFFFF){ + *((uint16*)eax) = 0; + entry_objects = (rct_object_entry*)(eax + 2); + } + + scenery_set->entry_count = 0; + scenery_set->var_107 = 0; + + for (; *chunk != 0xFF; chunk += sizeof(rct_object_entry)){ + scenery_set->var_107++; + + if (entry_objects != NULL){ + memcpy(entry_objects, chunk, sizeof(rct_object_entry)); + entry_objects++; + (*(eax + 1))++; + } + uint8 entry_type; + uint8 entry_index = 0; + if (!find_object_in_entry_group((rct_object_entry*)chunk, &entry_type, &entry_index)) + continue; + + uint16 scenery_entry = entry_index; + + switch (entry_type){ + case OBJECT_TYPE_SMALL_SCENERY: + break; + case OBJECT_TYPE_LARGE_SCENERY: + scenery_entry |= 0x300; + break; + case OBJECT_TYPE_WALLS: + scenery_entry |= 0x200; + break; + case OBJECT_TYPE_PATH_BITS: + scenery_entry |= 0x100; + break; + default: + scenery_entry |= 0x400; + break; + } + + scenery_set->scenery_entries[scenery_set->entry_count++] = scenery_entry; + } + + chunk++; + + scenery_set->image = object_chunk_load_image_directory(&chunk); + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_scenery_set_entry* scenery_set = (rct_scenery_set_entry*)esi; + scenery_set->name = 0; + scenery_set->image = 0; + scenery_set->entry_count = 0; + scenery_set->var_107 = 0; + + memset(scenery_set->scenery_entries, 0, 256); + } + else if ((flags & 0xFF) == 2){ + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + + rct_scenery_set_entry* scenery_set = (rct_scenery_set_entry*)ebp; + + if (!((flags >> 8) & 0xFF)) + { + int image_id = scenery_set->image; + + image_id += 0x20600001; + + gfx_draw_sprite(dpi, image_id, x - 15, y - 14, 0); + } + else{ + RCT2_GLOBAL(0x13CE952, uint16) = scenery_set->var_107; + + gfx_draw_string_left(dpi, 3167, RCT2_ADDRESS(0x13CE952, void), 0, x, y); + } + } + return flags; +} + + +//rct2: 0x00666E42 +int paint_park_entrance_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_entrance_type* entrance_type = (rct_entrance_type*)esi; + uint8* pStringTable = (uint8*)(esi + sizeof(rct_entrance_type)); + + entrance_type->string_idx = object_get_localised_text(&pStringTable, ecx, ebx, 0); + + entrance_type->image_id = object_chunk_load_image_directory(&pStringTable); + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_entrance_type* entrance_type = (rct_entrance_type*)esi; + entrance_type->string_idx = 0; + entrance_type->image_id = 0; + } + else if ((flags & 0xFF) == 2){ + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + if (!((flags >> 8) & 0xFF)) + { + rct_entrance_type* entrance_type = (rct_entrance_type*)ebp; + + dpi = clip_drawpixelinfo(dpi, x - 56, 112, y - 56, 112); + if (dpi == NULL) return flags; + + int image_id = entrance_type->image_id; + + gfx_draw_sprite(dpi, image_id + 1, 24, 68, ebp); + gfx_draw_sprite(dpi, image_id, 56, 84, ebp); + gfx_draw_sprite(dpi, image_id + 2, 88, 100, ebp); + + rct2_free(dpi); + } + } + return flags; +} + +//rct2: 0x006E6E2A +int paint_water_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_water_type* water_type = (rct_water_type*)esi; + + uint8_t* pStringTable = (uint8_t*)(esi + sizeof(rct_water_type)); + water_type->string_idx = object_get_localised_text(&pStringTable, ecx, ebx, 0); + + int image_id = object_chunk_load_image_directory(&pStringTable); + water_type->image_id = image_id; + water_type->var_06 = image_id + 1; + water_type->var_0A = image_id + 4; + + if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; + + if (RCT2_GLOBAL(0x9ADAFD, uint8_t) == 0) + { + load_palette(); + gfx_invalidate_screen(); + } + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_water_type* water_type = (rct_water_type*)esi; + water_type->string_idx = 0; + water_type->image_id = 0; + water_type->var_06 = 0; + water_type->var_0A = 0; + } + else if ((flags & 0xFF) == 2){ + return 0; + } + else if ((flags & 0xFF) == 3){ + if (!((flags >> 8) & 0xFF)) + gfx_draw_string_centred(dpi, 3326, ecx, edx, 0, (void*)esi); + } + return flags; +} + +//rct2: 0x0066B355 +int paint_stex_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dpi, int esi, int ebp) +{ + if ((flags & 0xFF) == 0){ + // Object Load + + rct_stex_entry* stex_entry = (rct_stex_entry*)esi; + uint8_t* pStringTable = (uint8_t*)(esi + 8); + stex_entry->scenario_name = object_get_localised_text(&pStringTable, ecx, ebx, 0); + stex_entry->park_name = object_get_localised_text(&pStringTable, ecx, ebx, 1); + stex_entry->details = object_get_localised_text(&pStringTable, ecx, ebx, 2); + if (RCT2_GLOBAL(0x9ADAF4, int) != -1) RCT2_GLOBAL(0x9ADAF4, uint16_t*)[0] = 0; + } + else if ((flags & 0xFF) == 1){ + // Object Unload + + rct_stex_entry* stex_entry = (rct_stex_entry*)esi; + stex_entry->scenario_name = 0; + stex_entry->park_name = 0; + stex_entry->details = 0; + } + else if ((flags & 0xFF) == 2){ + return 0; + } + else if ((flags & 0xFF) == 3){ + int x = ecx, y = edx; + rct_stex_entry* stex_entry = (rct_stex_entry*)ebp; + rct_window* w = (rct_window*)esi; + + if (!((flags >> 8) & 0xFF)) { + gfx_draw_string_centred(dpi, 0xCFE, x, y, 0, NULL); + } + else{ + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = stex_entry->details; + int width = w->x + w->width - 4 - x; + gfx_draw_string_left_wrapped(dpi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, x, y, width, 3168, 0); + } + } + return flags; } int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp) { - //if (type == OBJECT_TYPE_SCENARIO_TEXT){ - // if (eax == 0) return object_scenario_load_custom_text((char*)esi); - //} - return RCT2_CALLPROC_X(RCT2_ADDRESS(0x0098D9D4, uint32)[type], eax, ebx, ecx, edx, esi, edi, ebp) & 0x100; + switch (type) + { + case OBJECT_TYPE_RIDE: + return paint_ride_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_SMALL_SCENERY: + return paint_small_scenery(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_LARGE_SCENERY: + return paint_large_scenery(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_WALLS: + return paint_wall(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_BANNERS: + return paint_banner(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_PATHS: + return paint_path_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_PATH_BITS: + return paint_path_bit(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_SCENERY_SETS: + return paint_scenery_set(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_PARK_ENTRANCE: + return paint_park_entrance_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_WATER: + return paint_water_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + case OBJECT_TYPE_SCENARIO_TEXT: + return paint_stex_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + default: + assert(false); + return 0; + } } /** - * + * * rct2: 0x006A9428 */ int object_get_scenario_text(rct_object_entry *entry) { - // RCT2_CALLPROC_X(0x006A9428, 0, 0, 0, 0, 0, 0, (int)entry); return; - - int i; rct_object_entry *installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); - for (i = 0; i < RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, sint32); i++) { - if (object_entry_compare(installedObject, entry)) { - char path[260]; - char *objectPath = (char*)installedObject + 16; - subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath); - rct_object_entry openedEntry; - FILE *file = fopen(path, "rb"); - if (file != NULL) { - fread(&openedEntry, sizeof(rct_object_entry), 1, file); - if (object_entry_compare(&openedEntry, entry)) { - - // Get chunk size - char *pos = (char*)installedObject + 16; - // Skip file name - while (*pos++); - - // Read chunk - int chunkSize = *((uint32*)pos); - char *chunk; - if (chunkSize == 0xFFFFFFFF) { - chunk = malloc(0x600000); - chunkSize = sawyercoding_read_chunk(file, chunk); - chunk = realloc(chunk, chunkSize); - } else { - chunk = malloc(chunkSize); - sawyercoding_read_chunk(file, chunk); - } - fclose(file); - - // Calculate and check checksum - if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) { - RCT2_GLOBAL(0x00F42BD9, uint8) = 2; - free(chunk); - return 0; - } - - if (object_paint(openedEntry.flags & 0x0F, 2, 0, 0, 0, (int)chunk, 0, 0)) { - RCT2_GLOBAL(0x00F42BD9, uint8) = 3; - free(chunk); - return 0; - } - - int yyy = RCT2_GLOBAL(0x009ADAF0, uint32); - RCT2_GLOBAL(0x009ADAF0, uint32) = 0x726E; - RCT2_GLOBAL(0x009ADAF8, uint32) = (int)chunk; - *((rct_object_entry*)0x00F42BC8) = openedEntry; - - RCT2_GLOBAL(0x009ADAFC, uint8) = 255; - RCT2_GLOBAL(0x009ADAFD, uint8) = 1; - object_paint(openedEntry.flags & 0x0F, 0, 0, 0, 0, (int)chunk, 0, 0); - RCT2_GLOBAL(0x009ADAFC, uint8) = 0; - RCT2_GLOBAL(0x009ADAFD, uint8) = 0; - RCT2_GLOBAL(0x009ADAF0, uint32) = yyy; - return 1; - } - fclose(file); - } - } - installedObject = object_get_next(installedObject); + installedObject = object_list_find(entry); + + if (installedObject == NULL){ + log_error("Object not found: %.8s", entry->name); + RCT2_GLOBAL(0x00F42BD9, uint8) = 0; + return 0; } + char path[260]; + char *objectPath = (char*)installedObject + 16; + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath); + + rct_object_entry openedEntry; + FILE *file = fopen(path, "rb"); + if (file != NULL) { + fread(&openedEntry, sizeof(rct_object_entry), 1, file); + if (object_entry_compare(&openedEntry, entry)) { + + // Skip over the object entry + char *pos = (char*)installedObject + sizeof(rct_object_entry); + // Skip file name + while (*pos++); + + // Read chunk + int chunkSize = *((uint32*)pos); + + char *chunk; + if (chunkSize == 0xFFFFFFFF) { + chunk = malloc(0x600000); + chunkSize = sawyercoding_read_chunk(file, chunk); + chunk = realloc(chunk, chunkSize); + } + else { + chunk = malloc(chunkSize); + sawyercoding_read_chunk(file, chunk); + } + fclose(file); + + // Calculate and check checksum + if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) { + log_error("Opened object failed calculated checksum."); + RCT2_GLOBAL(0x00F42BD9, uint8) = 2; + free(chunk); + return 0; + } + + if (object_paint(openedEntry.flags & 0x0F, 2, 0, 0, 0, (int)chunk, 0, 0)) { + // This is impossible for STEX entries to fail. + log_error("Opened object failed paitn test."); + RCT2_GLOBAL(0x00F42BD9, uint8) = 3; + free(chunk); + return 0; + } + + // Save the real total images. + int total_no_images = RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32); + + // This is being changed to force the images to be loaded into a different + // image id. + RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) = 0x726E; + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, uint32) = (int)chunk; + // Not used anywhere. + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_OBJECT, rct_object_entry) = openedEntry; + + // Tell text to be loaded into a different address + RCT2_GLOBAL(0x009ADAFC, uint8) = 255; + // Not used?? + RCT2_GLOBAL(0x009ADAFD, uint8) = 1; + object_paint(openedEntry.flags & 0x0F, 0, 0, 0, 0, (int)chunk, 0, 0); + // Tell text to be loaded into normal address + RCT2_GLOBAL(0x009ADAFC, uint8) = 0; + // Not used?? + RCT2_GLOBAL(0x009ADAFD, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) = total_no_images; + return 1; + } + log_error("Opened object didn't match."); + fclose(file); + return 0; + } + log_error("File failed to open."); RCT2_GLOBAL(0x00F42BD9, uint8) = 0; return 0; } /** - * + * * rct2: 0x006A982D */ void object_free_scenario_text() { - if (RCT2_GLOBAL(0x009ADAF8, void*) != NULL) { - free(RCT2_GLOBAL(0x009ADAF8, void*)); - RCT2_GLOBAL(0x009ADAF8, void*) = NULL; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*) != NULL) { + rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*)); + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*) = NULL; } } @@ -515,7 +1610,7 @@ rct_object_entry *object_get_next(rct_object_entry *entry) // Skip filename while (*pos++); - // Skip + // Skip no of images pos += 4; // Skip name @@ -525,13 +1620,29 @@ rct_object_entry *object_get_next(rct_object_entry *entry) pos += 4; // Skip - pos += *pos++ * 16; + pos += *pos * 16 + 1; // Skip theme objects - pos += *pos++ * 16; + pos += *pos * 16 + 1; // Skip pos += 4; return (rct_object_entry*)pos; +} + +char *object_get_name(rct_object_entry *entry) +{ + uint8 *pos = (uint8*)entry; + + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + return pos; } \ No newline at end of file diff --git a/src/object.h b/src/object.h index 70be1a0f5a..cfe41692d6 100644 --- a/src/object.h +++ b/src/object.h @@ -67,6 +67,17 @@ typedef struct { rct_object_entry_extended *entries; } rct_object_entry_group; +typedef struct { + uint8 category[2]; + +} rct_ride_filters; + +typedef struct { + union { + rct_ride_filters ride; + }; +} rct_object_filters; + extern rct_object_entry_group object_entry_groups[]; int object_load_entry(const char *path, rct_object_entry *outEntry); @@ -76,6 +87,7 @@ int object_read_and_load_entries(FILE *file); int object_load_packed(FILE *file); void object_unload_all(); +int check_object_entry(rct_object_entry *entry); int object_load(int groupIndex, rct_object_entry *entry, int* chunk_size); int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSize, const rct_object_entry *installedObject); void object_unload(int groupIndex, rct_object_entry_extended *entry); @@ -86,8 +98,14 @@ int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry *entry, const char *data, int dataLength); int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); rct_object_entry *object_get_next(rct_object_entry *entry); -int sub_6A9F42(FILE *file, rct_object_entry* entry); +int write_object_file(FILE *file, rct_object_entry* entry); +void reset_loaded_objects(); +int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); rct_object_entry *object_list_find(rct_object_entry *entry); +char *object_get_name(rct_object_entry *entry); + +rct_object_filters *get_object_filter(int index); + #endif \ No newline at end of file diff --git a/src/object_list.c b/src/object_list.c index 70b0b037b7..7c11b55a7b 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -22,12 +22,13 @@ #include "localisation/localisation.h" #include "object.h" #include "platform/platform.h" -#include "platform/osinterface.h" #include "ride/track.h" #include "util/sawyercoding.h" +#include "game.h" #define OBJECT_ENTRY_GROUP_COUNT 11 #define OBJECT_ENTRY_COUNT 721 +#define FILTER_VERSION 1 typedef struct { uint32 total_files; @@ -70,29 +71,92 @@ int object_entry_group_encoding[] = { // 0x98D97C chunk address', 0x98D980 object_entries rct_object_entry_group object_entry_groups[] = { (uint8**)(0x009ACFA4 ), (rct_object_entry_extended*)(0x00F3F03C ), // rides - (uint8**)(0x009ACFA4 + (128 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (128 * 20)), // small scenery - (uint8**)(0x009ACFA4 + (380 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (380 * 20)), // large scenery - (uint8**)(0x009ACFA4 + (508 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (508 * 20)), // walls - (uint8**)(0x009ACFA4 + (636 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (636 * 20)), // banners - (uint8**)(0x009ACFA4 + (668 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (668 * 20)), // paths - (uint8**)(0x009ACFA4 + (684 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (684 * 20)), // path bits - (uint8**)(0x009ACFA4 + (699 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (699 * 20)), // scenery sets - (uint8**)(0x009ACFA4 + (718 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (718 * 20)), // park entrance - (uint8**)(0x009ACFA4 + (719 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (719 * 20)), // water - (uint8**)(0x009ACFA4 + (720 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (720 * 20)) // scenario text + (uint8**)(0x009ACFA4 + (128 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (128 * 20)), // small scenery 0x009AD1A4, 0xF2FA3C + (uint8**)(0x009ACFA4 + (380 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (380 * 20)), // large scenery 0x009AD594, 0xF40DEC + (uint8**)(0x009ACFA4 + (508 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (508 * 20)), // walls 0x009AD794, 0xF417EC + (uint8**)(0x009ACFA4 + (636 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (636 * 20)), // banners 0x009AD994, 0xF421EC + (uint8**)(0x009ACFA4 + (668 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (668 * 20)), // paths 0x009ADA14, 0xF4246C + (uint8**)(0x009ACFA4 + (684 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (684 * 20)), // path bits 0x009ADA54, 0xF425AC + (uint8**)(0x009ACFA4 + (699 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (699 * 20)), // scenery sets 0x009ADA90, 0xF426D8 + (uint8**)(0x009ACFA4 + (718 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (718 * 20)), // park entrance 0x009ADADC, 0xF42854 + (uint8**)(0x009ACFA4 + (719 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (719 * 20)), // water 0x009ADAE0, 0xF42868 + (uint8**)(0x009ACFA4 + (720 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (720 * 20)) // scenario text 0x009ADAE4, 0xF4287C }; static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int fileDateModifiedChecksum); static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileDateModifiedChecksum, int currentItemOffset); void object_list_create_hash_table(); -static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* installed_entry, const char* path); +static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* installed_entry, const char* path, rct_object_filters* filter); +static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object_filters* filter); -static void get_plugin_path(char *path) +static rct_object_filters *_installedObjectFilters = NULL; + +static void get_plugin_path(char *outPath) { - char *homePath = osinterface_get_orct2_homefolder(); - sprintf(path, "%s%c%s", homePath, osinterface_get_path_separator(), "plugin.dat"); - free(homePath); + platform_get_user_directory(outPath, NULL); + strcat(outPath, "plugin.dat"); +} + +static void object_list_sort() +{ + rct_object_entry **objectBuffer, *newBuffer, *entry, *destEntry, *lowestEntry; + rct_object_filters *newFilters, *destFilter; + int numObjects, i, j, bufferSize, entrySize, lowestIndex; + char *objectName, *lowestString; + uint8 *copied; + + objectBuffer = &RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + numObjects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, sint32); + copied = calloc(numObjects, sizeof(uint8)); + + // Get buffer size + entry = *objectBuffer; + for (i = 0; i < numObjects; i++) + entry = object_get_next(entry); + bufferSize = (int)entry - (int)*objectBuffer; + + // Create new buffer + newBuffer = rct2_malloc(bufferSize); + destEntry = newBuffer; + if (_installedObjectFilters) { + newFilters = malloc(numObjects * sizeof(rct_object_filters)); + destFilter = newFilters; + } + + // Copy over sorted objects + for (i = 0; i < numObjects; i++) { + // Find next lowest string + lowestString = NULL; + entry = *objectBuffer; + for (j = 0; j < numObjects; j++) { + if (!copied[j]) { + objectName = object_get_name(entry); + if (lowestString == NULL || strcmp(objectName, lowestString) < 0) { + lowestEntry = entry; + lowestString = objectName; + lowestIndex = j; + } + } + entry = object_get_next(entry); + } + entrySize = object_get_length(lowestEntry); + memcpy(destEntry, lowestEntry, entrySize); + destEntry = (rct_object_entry*)((int)destEntry + entrySize); + if (_installedObjectFilters) + destFilter[i] = _installedObjectFilters[lowestIndex]; + copied[lowestIndex] = 1; + } + + // Replace old buffer + rct2_free(*objectBuffer); + *objectBuffer = newBuffer; + if (_installedObjectFilters) { + free(_installedObjectFilters); + _installedObjectFilters = newFilters; + } + + free(copied); } /** @@ -104,39 +168,33 @@ static void object_list_examine() int i; rct_object_entry *object; + RCT2_GLOBAL(RCT2_ADDRESS_CUSTOM_OBJECTS_INSTALLED, uint8) = 0; + object = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); for (i = 0; i < RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, sint32); i++) { - if (object->flags & 0xF0) - RCT2_GLOBAL(0x00F42BDA, uint8) |= 1; + if (!(object->flags & 0xF0)) + RCT2_GLOBAL(RCT2_ADDRESS_CUSTOM_OBJECTS_INSTALLED, uint8) |= 1; object = object_get_next(object); } + object_list_sort(); // Create a search index object_list_create_hash_table(); } -/** - * - * rct2: 0x006DED68 - */ -void reset_9E32F8() +/* rct2: 0x006A9FC0 */ +void reset_loaded_objects() { - uint8* edi = RCT2_ADDRESS(0x009E32F8, uint8); - memset(edi, 0xFF, 90); -} + reset_type_to_ride_entry_index_map(); -void sub_6A9FC0() -{ - reset_9E32F8(); - - RCT2_GLOBAL(0x009ADAF0, uint32) = 0xF26E; + RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) = 0xF26E; for (int type = 0; type < 11; ++type){ for (int j = 0; j < object_entry_group_counts[type]; j++){ uint8* chunk = object_entry_groups[type].chunks[j]; if (chunk != (uint8*)-1) - object_paint(type, 0, 0, 0, 0, (int)chunk, 0, 0); + object_paint(type, 0, j, type, 0, (int)chunk, 0, 0); } } } @@ -153,21 +211,23 @@ static int object_list_query_directory(int *outTotalFiles, uint64 *outTotalFileS // Enumerate through each object in the directory enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char)); - if (enumFileHandle != INVALID_HANDLE) { - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { - totalFiles++; - totalFileSize += enumFileInfo.size; - fileDateModifiedChecksum ^= - (uint32)(enumFileInfo.last_modified >> 32) ^ - (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); - fileDateModifiedChecksum = ror32(fileDateModifiedChecksum, 5); - } - platform_enumerate_files_end(enumFileHandle); + if (enumFileHandle == INVALID_HANDLE) + return 0; + + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { + totalFiles++; + totalFileSize += enumFileInfo.size; + fileDateModifiedChecksum ^= + (uint32)(enumFileInfo.last_modified >> 32) ^ + (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); + fileDateModifiedChecksum = ror32(fileDateModifiedChecksum, 5); } + platform_enumerate_files_end(enumFileHandle); *outTotalFiles = totalFiles; *outTotalFileSize = totalFileSize; *outFileDateModifiedChecksum = fileDateModifiedChecksum; + return 1; } /** @@ -192,10 +252,12 @@ void object_list_load() // Reload object list - if (RCT2_GLOBAL(0x9AA00D, uint8) != 0) - RCT2_GLOBAL(0x9AA00D, uint8) = 0; + // RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_OBJECTS used to control if this was the first time loading objects + // and display the starting RCT2 for the first time message. + //if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_OBJECTS, uint8) != 0) + // RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FIRST_TIME_LOAD_OBJECTS, uint8) = 0; - sub_6A9FC0(); + reset_loaded_objects(); // Dispose installed object list if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, sint32) != -1) { @@ -206,15 +268,23 @@ void object_list_load() RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_malloc(4096); if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, int) == -1){ - RCT2_CALLPROC_X(0x006E3838, 0x343, 0xC5A, 0, 0, 0, 0, 0); + log_error("Failed to allocate memory for object list"); + rct2_exit_reason(835, 3162); return; } uint32 fileCount = 0; + uint32 objectCount = 0; uint32 current_item_offset = 0; + RCT2_GLOBAL(RCT2_ADDRESS_ORIGINAL_RCT2_OBJECT_COUNT, uint32) = 0; log_verbose("building cache of available objects..."); + if (_installedObjectFilters) { + free(_installedObjectFilters); + _installedObjectFilters = NULL; + } + enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char)); if (enumFileHandle != INVALID_HANDLE) { uint32 installed_buffer_size = 0x1000; @@ -226,7 +296,8 @@ void object_list_load() installed_buffer_size += 0x1000; RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_realloc(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), installed_buffer_size); if (RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, int) == -1){ - RCT2_CALLPROC_X(0x006E3838, 0x343, 0xC5A, 0, 0, 0, 0, 0); + log_error("Failed to allocate memory for object list"); + rct2_exit_reason(835, 3162); return; } } @@ -234,22 +305,31 @@ void object_list_load() char path[MAX_PATH]; subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), enumFileInfo.path); - rct_object_entry* entry = RCT2_ADDRESS(0x00F42B74, rct_object_entry); - if (!object_load_entry(path, entry)) + rct_object_entry entry; + if (!object_load_entry(path, &entry)) continue; - rct_object_entry* installed_entry = (rct_object_entry*)(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*) + current_item_offset); + if (_installedObjectFilters) + _installedObjectFilters = realloc(_installedObjectFilters, sizeof(rct_object_filters) * (objectCount + 1)); + else + _installedObjectFilters = malloc(sizeof(rct_object_filters) * (objectCount + 1)); - current_item_offset += install_object_entry(entry, installed_entry, enumFileInfo.path); + rct_object_entry* installed_entry = (rct_object_entry*)(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*) + current_item_offset); + rct_object_filters filter; + + current_item_offset += install_object_entry(&entry, installed_entry, enumFileInfo.path, &filter); + _installedObjectFilters[objectCount] = filter; + + objectCount++; } platform_enumerate_files_end(enumFileHandle); } - sub_6A9FC0(); + reset_loaded_objects(); object_list_cache_save(fileCount, totalFileSize, fileDateModifiedChecksum, current_item_offset); - // + // Reload track list ride_list_item ride_list; ride_list.entry_index = 0xFC; ride_list.type = 0xFC; @@ -263,6 +343,7 @@ static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int file char path[MAX_PATH]; FILE *file; rct_plugin_header pluginHeader; + uint32 filterVersion = 0; log_verbose("loading object list cache (plugin.dat)"); @@ -291,12 +372,41 @@ static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int file if (fread(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), pluginHeader.object_list_size, 1, file) == 1) { RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) = pluginHeader.object_list_no_items; - fclose(file); - sub_6A9FC0(); - object_list_examine(); - return 1; + if (pluginHeader.object_list_no_items != (pluginHeader.total_files & 0xFFFFFF)) + log_error("Potential mismatch in file numbers. Possible corrupt file. Consider deleting plugin.dat."); + + if (fread(&filterVersion, sizeof(filterVersion), 1, file) == 1) { + if (filterVersion == FILTER_VERSION) { + if (_installedObjectFilters) + free(_installedObjectFilters); + _installedObjectFilters = malloc(sizeof(rct_object_filters) * pluginHeader.object_list_no_items); + if (fread(_installedObjectFilters, sizeof(rct_object_filters) * pluginHeader.object_list_no_items, 1, file) == 1) { + + fclose(file); + reset_loaded_objects(); + object_list_examine(); + return 1; + } + } + } + log_info("Filter version updated... updating object list cache"); } } + else if (pluginHeader.total_files != totalFiles) { + int fileCount = totalFiles - pluginHeader.total_files; + if (fileCount < 0) { + log_info("%d object removed... updating object list cache", abs(fileCount)); + } else { + log_info("%d object added... updating object list cache", fileCount); + } + } else if (pluginHeader.total_file_size != totalFileSize) { + log_info("Objects files size changed... updating object list cache"); + } else if (pluginHeader.date_modified_checksum != fileDateModifiedChecksum) { + log_info("Objects files have been updated... updating object list cache"); + } + + fclose(file); + return 0; } fclose(file); @@ -310,6 +420,7 @@ static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileD char path[MAX_PATH]; FILE *file; rct_plugin_header pluginHeader; + uint32 filterVersion = FILTER_VERSION; log_verbose("saving object list cache (plugin.dat)"); @@ -328,11 +439,13 @@ static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileD fwrite(&pluginHeader, sizeof(rct_plugin_header), 1, file); fwrite(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*), pluginHeader.object_list_size, 1, file); + fwrite(&filterVersion, sizeof(filterVersion), 1, file); + fwrite(_installedObjectFilters, sizeof(rct_object_filters) * RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32), 1, file); fclose(file); return 1; } -static int check_object_entry(rct_object_entry *entry) +int check_object_entry(rct_object_entry *entry) { uint32 *dwords = (uint32*)entry; return (0xFFFFFFFF & dwords[0] & dwords[1] & dwords[2] & dwords[3]) + 1 != 0; @@ -351,15 +464,15 @@ void set_load_objects_fail_reason(){ format_string(string_buffer, 3323, 0); //Missing object data, ID: RCT2_CALLPROC_X(0x6AB344, 0, 0, 0, 0, 0, (int)string_buffer, 0x13CE952); - RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; - RCT2_GLOBAL(0x9AC31C, uint16) = 3165; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3165; return; } char* exapansion_name = &RCT2_ADDRESS(RCT2_ADDRESS_EXPANSION_NAMES, char)[128 * expansion]; if (*exapansion_name == '\0'){ - RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; - RCT2_GLOBAL(0x9AC31C, uint16) = 3325; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3325; return; } @@ -367,8 +480,8 @@ void set_load_objects_fail_reason(){ format_string(string_buffer, 3324, 0); // Requires expansion pack strcat(string_buffer, exapansion_name); - RCT2_GLOBAL(0x9AC31B, uint8) = 0xFF; - RCT2_GLOBAL(0x9AC31C, uint16) = 3165; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3165; } /** @@ -388,6 +501,7 @@ int object_read_and_load_entries(FILE *file) entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry)); sawyercoding_read_chunk(file, (uint8*)entries); + uint8 load_fail = 0; // Load each object for (i = 0; i < OBJECT_ENTRY_COUNT; i++) { if (!check_object_entry(&entries[i])) @@ -405,14 +519,18 @@ int object_read_and_load_entries(FILE *file) if (!object_load(entryGroupIndex, &entries[i], NULL)) { log_error("failed to load entry: %.8s", entries[i].name); memcpy((char*)0x13CE952, &entries[i], sizeof(rct_object_entry)); - free(entries); - object_unload_all(); - RCT2_GLOBAL(0x14241BC, uint32) = 0; - return 0; + load_fail = 1; } } - free(entries); + free(entries); + if (load_fail){ + object_unload_all(); + RCT2_GLOBAL(0x14241BC, uint32) = 0; + return 0; + } + + log_verbose("finished loading required objects"); return 1; } @@ -431,13 +549,14 @@ void object_unload_all() if (object_entry_groups[i].chunks[j] != (uint8*)0xFFFFFFFF) object_unload(j, &object_entry_groups[i].entries[j]); - sub_6A9FC0(); + reset_loaded_objects(); } uint32 _installedObjectHashTableSize; rct_object_entry ** _installedObjectHashTable = NULL; + uint32 _installedObjectHashTableCollisions; uint32 object_get_hash_code(rct_object_entry *object) @@ -478,12 +597,36 @@ void object_list_create_hash_table() // Set hash table slot _installedObjectHashTable[index] = installedObject; - - // Next installde object + + // Next installed object installedObject = object_get_next(installedObject); } } +/* 0x006A9DA2 + * bl = entry_index + * ecx = entry_type + */ +int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index){ + *entry_type = entry->flags & 0xF; + + rct_object_entry_group entry_group = object_entry_groups[*entry_type]; + for (*entry_index = 0; + *entry_index < object_entry_group_counts[*entry_type]; + ++(*entry_index), + entry_group.chunks++, + entry_group.entries++){ + + if (*entry_group.chunks == (uint8*)-1) continue; + + if (object_entry_compare((rct_object_entry*)entry_group.entries, entry))break; + } + + if (*entry_index == object_entry_group_counts[*entry_type])return 0; + return 1; +} + + rct_object_entry *object_list_find(rct_object_entry *entry) { uint32 hash = object_get_hash_code(entry); @@ -503,7 +646,7 @@ rct_object_entry *object_list_find(rct_object_entry *entry) /* Installs an object_entry at the desired installed_entry address * Returns the size of the new entry. Will return 0 on failure. */ -static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* installed_entry, const char* path){ +static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* installed_entry, const char* path, rct_object_filters* filter){ uint8* installed_entry_pointer = (uint8*) installed_entry; /** Copy all known information into the install entry **/ @@ -515,12 +658,14 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in // Chunk size is set to unknown *((sint32*)installed_entry_pointer) = -1; + // No unknown objects set to 0 *(installed_entry_pointer + 4) = 0; + // No theme objects set to 0 *((sint32*)(installed_entry_pointer + 5)) = 0; *((uint16*)(installed_entry_pointer + 9)) = 0; *((uint32*)(installed_entry_pointer + 11)) = 0; - RCT2_GLOBAL(0x9ADAF0, uint32) = 0xF26E; + RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) = 0xF26E; RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)++; @@ -534,6 +679,7 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in /** Use object_load_file to fill in missing chunk information **/ int chunk_size; if (!object_load_file(-1, entry, &chunk_size, installed_entry)){ + log_error("Object Load File failed. Potentially corrupt file: %.8s", entry->name); RCT2_GLOBAL(0x009ADAF4, sint32) = -1; RCT2_GLOBAL(0x009ADAFD, uint8) = 0; RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)--; @@ -547,9 +693,10 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in RCT2_GLOBAL(0x009ADAFD, uint8) = 0; if ((entry->flags & 0xF0) == 0x80) { - RCT2_GLOBAL(0x00F42B70, uint32)++; - if (RCT2_GLOBAL(0x00F42B70, uint32) > 772){ - RCT2_GLOBAL(0x00F42B70, uint32)--; + RCT2_GLOBAL(RCT2_ADDRESS_ORIGINAL_RCT2_OBJECT_COUNT, uint32)++; + if (RCT2_GLOBAL(RCT2_ADDRESS_ORIGINAL_RCT2_OBJECT_COUNT, uint32) > 772){ + log_error("Incorrect number of vanilla RCT2 objects."); + RCT2_GLOBAL(RCT2_ADDRESS_ORIGINAL_RCT2_OBJECT_COUNT, uint32)--; RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32)--; object_unload(objectType, (rct_object_entry_extended*)entry); return 0; @@ -560,28 +707,34 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in uint8* chunk = RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_CHUNK_POINTER, uint8*); // Loaded in object_load - // When made of two parts i.e Wooden Roller Coaster (Dream Woodie Cars); - if (objectType == OBJECT_TYPE_RIDE && !(*((uint32*)(chunk + 8)) & 0x1000)) { - rct_string_id obj_string = chunk[12]; + load_object_filter(entry, chunk, filter); + + + // When made of two parts i.e Wooden Roller Coaster (Dream Woodie Cars) + if ((objectType == OBJECT_TYPE_RIDE) && !((((rct_ride_type*)chunk)->flags) & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME)) { + rct_ride_type* ride_type = (rct_ride_type*)chunk; + rct_string_id obj_string = ride_type->ride_type[0]; if (obj_string == 0xFF){ - obj_string = chunk[13]; + obj_string = ride_type->ride_type[1]; if (obj_string == 0xFF) { - obj_string = chunk[14]; + obj_string = ride_type->ride_type[2]; } } - obj_string += 2; - format_string(installed_entry_pointer, obj_string, 0); + format_string(installed_entry_pointer, obj_string + 2, 0); strcat(installed_entry_pointer, "\t ("); - strcat(installed_entry_pointer, language_get_string(RCT2_GLOBAL(0x00F42BBC, uint32))); + strcat(installed_entry_pointer, language_get_string((rct_string_id)RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32))); strcat(installed_entry_pointer, ")"); while (*installed_entry_pointer++); } else{ - strcpy(installed_entry_pointer, language_get_string(RCT2_GLOBAL(0x00F42BBC, uint32))); + strcpy(installed_entry_pointer, language_get_string((rct_string_id)RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32))); while (*installed_entry_pointer++); } - *((uint32*)installed_entry_pointer) = RCT2_GLOBAL(0x009ADAF0, uint32) - 0xF26E; + + // This is deceptive. Due to setting the total no images earlier to 0xF26E + // this is actually the no_images in this entry. + *((uint32*)installed_entry_pointer) = RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_NO_IMAGES, uint32) - 0xF26E; installed_entry_pointer += 4; uint8* esi = RCT2_ADDRESS(0x00F42BDB, uint8); @@ -608,4 +761,30 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in object_unload(objectType, (rct_object_entry_extended*)entry); return size_of_object; -} \ No newline at end of file +} + +static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object_filters* filter) +{ + switch (entry->flags & 0xF) { + case OBJECT_TYPE_RIDE: + filter->ride.category[0] = ((rct_ride_type*)chunk)->category[0]; + filter->ride.category[1] = ((rct_ride_type*)chunk)->category[1]; + break; + case OBJECT_TYPE_SMALL_SCENERY: + case OBJECT_TYPE_LARGE_SCENERY: + case OBJECT_TYPE_WALLS: + case OBJECT_TYPE_BANNERS: + case OBJECT_TYPE_PATHS: + case OBJECT_TYPE_PATH_BITS: + case OBJECT_TYPE_SCENERY_SETS: + case OBJECT_TYPE_PARK_ENTRANCE: + case OBJECT_TYPE_WATER: + case OBJECT_TYPE_SCENARIO_TEXT: + break; + } +} + +rct_object_filters *get_object_filter(int index) +{ + return &_installedObjectFilters[index]; +} diff --git a/src/openrct2.c b/src/openrct2.c index 36dd388bdc..83875fa3d6 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -25,72 +25,208 @@ #include "config.h" #include "editor.h" #include "localisation/localisation.h" +#include "network/http.h" #include "openrct2.h" #include "platform/platform.h" -#include "platform/osinterface.h" #include "util/sawyercoding.h" +#include "world/mapgen.h" int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE; char gOpenRCT2StartupActionPath[512] = { 0 }; +char gExePath[MAX_PATH]; + +// This should probably be changed later and allow a custom selection of things to initialise like SDL_INIT +bool gOpenRCT2Headless = false; + +bool gOpenRCT2ShowChangelog; /** If set, will end the OpenRCT2 game loop. Intentially private to this module so that the flag can not be set back to 0. */ int _finished; static void openrct2_loop(); +static void openrct2_copy_files_over(const char *originalDirectory, const char *newDirectory, const char *extension) +{ + char *ch, filter[MAX_PATH], oldPath[MAX_PATH], newPath[MAX_PATH]; + int fileEnumHandle; + file_info fileInfo; + + if (!platform_ensure_directory_exists(newDirectory)) { + log_error("Could not create directory %s.", newDirectory); + return; + } + + // Create filter path + strcpy(filter, originalDirectory); + ch = strchr(filter, '*'); + if (ch != NULL) + *ch = 0; + strcat(filter, "*"); + strcat(filter, extension); + + fileEnumHandle = platform_enumerate_files_begin(filter); + while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + strcpy(newPath, newDirectory); + strcat(newPath, fileInfo.path); + + strcpy(oldPath, originalDirectory); + ch = strchr(oldPath, '*'); + if (ch != NULL) + *ch = 0; + strcat(oldPath, fileInfo.path); + + if (!platform_file_exists(newPath)) + platform_file_copy(oldPath, newPath); + } + platform_enumerate_files_end(fileEnumHandle); + + fileEnumHandle = platform_enumerate_directories_begin(originalDirectory); + while (platform_enumerate_directories_next(fileEnumHandle, filter)) { + strcpy(newPath, newDirectory); + strcat(newPath, filter); + + strcpy(oldPath, originalDirectory); + ch = strchr(oldPath, '*'); + if (ch != NULL) + *ch = 0; + strcat(oldPath, filter); + + if (!platform_ensure_directory_exists(newPath)) { + log_error("Could not create directory %s.", newPath); + return; + } + openrct2_copy_files_over(oldPath, newPath, extension); + } + platform_enumerate_directories_end(fileEnumHandle); +} + +static void openrct2_set_exe_path() +{ + char exePath[MAX_PATH]; + char tempPath[MAX_PATH]; + char *exeDelimiter; + int pathEnd; + int exeDelimiterIndex; + + GetModuleFileName(NULL, exePath, MAX_PATH); + exeDelimiter = strrchr(exePath, platform_get_path_separator()); + exeDelimiterIndex = (int)(exeDelimiter - exePath); + pathEnd = strlen(exePath) - (strlen(exePath) - exeDelimiterIndex); + strncpy(tempPath, exePath, pathEnd); + tempPath[pathEnd] = '\0'; + _fullpath(gExePath, tempPath, MAX_PATH); +} + +/** + * Copy saved games and landscapes to user directory + */ +static void openrct2_copy_original_user_files_over() +{ + char path[MAX_PATH]; + + platform_get_user_directory(path, "save"); + openrct2_copy_files_over((char*)RCT2_ADDRESS_SAVED_GAMES_PATH, path, ".sv6"); + + platform_get_user_directory(path, "landscape"); + openrct2_copy_files_over((char*)RCT2_ADDRESS_LANDSCAPES_PATH, path, ".sc6"); +} + +bool openrct2_initialise() +{ + char userPath[MAX_PATH]; + + platform_get_user_directory(userPath, NULL); + if (!platform_ensure_directory_exists(userPath)) { + log_fatal("Could not create user directory (do you have write access to your documents folder?)"); + return false; + } + + openrct2_set_exe_path(); + + config_set_defaults(); + if (!config_open_default()) { + if (!config_find_or_browse_install_directory()) { + log_fatal("An RCT2 install directory must be specified!"); + return false; + } + } + + gOpenRCT2ShowChangelog = true; + if (gConfigGeneral.last_run_version != NULL && (strcmp(gConfigGeneral.last_run_version, OPENRCT2_VERSION) == 0)) + gOpenRCT2ShowChangelog = false; + gConfigGeneral.last_run_version = OPENRCT2_VERSION; + config_save_default(); + + // TODO add configuration option to allow multiple instances + if (!gOpenRCT2Headless && !platform_lock_single_instance()) { + log_fatal("OpenRCT2 is already running."); + return false; + } + + get_system_info(); + if (!gOpenRCT2Headless) { + audio_init(); + audio_get_devices(); + get_dsound_devices(); + } + language_open(gConfigGeneral.language); + http_init(); + + themes_set_default(); + themes_load_presets(); + + if (!rct2_init()) + return false; + + openrct2_copy_original_user_files_over(); + + Mixer_Init(NULL); + return true; +} + /** * Launches the game, after command line arguments have been parsed and processed. */ void openrct2_launch() { - config_load(); - - // TODO add configuration option to allow multiple instances - if (!platform_lock_single_instance()) { - fprintf(stderr, "OpenRCT2 is already running.\n"); - return; - } - - get_system_info(); - audio_init(); - audio_get_devices(); - get_dsound_devices(); - language_open(gGeneral_config.language); - if (!rct2_init()) - return; - - Mixer_Init(NULL); - - switch (gOpenRCT2StartupAction) { - case STARTUP_ACTION_INTRO: - RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 8; - break; - case STARTUP_ACTION_TITLE: + if (openrct2_initialise()) { RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_TITLE_DEMO; - break; - case STARTUP_ACTION_OPEN: - assert(gOpenRCT2StartupActionPath != NULL); - rct2_open_file(gOpenRCT2StartupActionPath); + switch (gOpenRCT2StartupAction) { + case STARTUP_ACTION_INTRO: + RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 8; + break; + case STARTUP_ACTION_TITLE: + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_TITLE_DEMO; + break; + case STARTUP_ACTION_OPEN: + assert(gOpenRCT2StartupActionPath != NULL); + rct2_open_file(gOpenRCT2StartupActionPath); - RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; - break; - case STARTUP_ACTION_EDIT: - if (strlen(gOpenRCT2StartupActionPath) == 0) - editor_load(); - else - editor_load_landscape(gOpenRCT2StartupActionPath); - break; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; + break; + case STARTUP_ACTION_EDIT: + if (strlen(gOpenRCT2StartupActionPath) == 0) { + editor_load(); + } else { + editor_load_landscape(gOpenRCT2StartupActionPath); + } + break; + } + openrct2_loop(); } - - openrct2_loop(); - osinterface_free(); + openrct2_dispose(); // HACK Some threads are still running which causes the game to not terminate. Investigation required! exit(gExitCode); } +void openrct2_dispose() +{ + http_dispose(); + language_close_all(); + platform_free(); +} + /** * Run the main game loop until the finished flag is set at 40fps (25ms interval). */ @@ -98,6 +234,8 @@ static void openrct2_loop() { uint32 currentTick, ticksElapsed, lastTick = 0; + log_verbose("begin openrct2 loop"); + _finished = 0; do { currentTick = SDL_GetTicks(); @@ -110,9 +248,9 @@ static void openrct2_loop() lastTick = currentTick; - osinterface_process_messages(); + platform_process_messages(); rct2_update(); - osinterface_draw(); + platform_draw(); } while (!_finished); } diff --git a/src/openrct2.h b/src/openrct2.h index f265c97833..120b09051f 100644 --- a/src/openrct2.h +++ b/src/openrct2.h @@ -32,8 +32,13 @@ enum { extern int gOpenRCT2StartupAction; extern char gOpenRCT2StartupActionPath[512]; +extern char gExePath[MAX_PATH]; +extern bool gOpenRCT2Headless; +extern bool gOpenRCT2ShowChangelog; +bool openrct2_initialise(); void openrct2_launch(); +void openrct2_dispose(); void openrct2_finish(); #endif \ No newline at end of file diff --git a/src/peep/peep.c b/src/peep/peep.c index 1a7dde9345..eac001cd5d 100644 --- a/src/peep/peep.c +++ b/src/peep/peep.c @@ -29,10 +29,19 @@ #include "../sprites.h" #include "../world/sprite.h" #include "../world/scenery.h" +#include "../management/marketing.h" #include "peep.h" #include "staff.h" static void peep_update(rct_peep *peep); +static int peep_has_empty_container(rct_peep* peep); +static int peep_has_food_standard_flag(rct_peep* peep); +static int peep_has_food_extra_flag(rct_peep* peep); +static int peep_empty_container_standard_flag(rct_peep* peep); +static int peep_empty_container_extra_flag(rct_peep* peep); +static int peep_should_find_bench(rct_peep* peep); +static void peep_stop_purchase_thought(rct_peep* peep, uint8 ride_type); +static void sub_693BAB(rct_peep* peep); const char *gPeepEasterEggNames[] = { "MICHAEL SCHUMACHER", @@ -111,22 +120,20 @@ int sub_68F3AE(rct_peep* peep){ peep->var_C4++; if ((peep->var_C4 & 0xF) != (peep->sprite_index & 0xF))return 1; - uint16 ebx = (peep->next_x | (peep->next_y << 8)) >> 5; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(ebx); + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); uint8 map_type = MAP_ELEMENT_TYPE_PATH; - if ((peep->next_z >> 8) & ((1 << 4) | (1 << 3))){ + if (peep->next_var_29 & ((1 << 4) | (1 << 3))){ map_type = MAP_ELEMENT_TYPE_SURFACE; } - int z = peep->next_z & 0xFF; + int z = peep->next_z; - for (;; map_element++){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == map_type){ + do { + if (map_element_get_type(map_element) == map_type){ if (z == map_element->base_height)return 1; } - if (map_element->flags & MAP_ELEMENT_FLAG_LAST_TILE)break; - } + } while (!map_element_is_last_for_tile(map_element++)); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; @@ -142,35 +149,122 @@ void sub_693B58(rct_peep* peep){ else{ ebx = RCT2_ADDRESS(0x981D8F, uint8)[peep->action]; } - if (ebx == peep->var_6E)return; + if (ebx == peep->action_sprite_type)return; invalidate_sprite((rct_sprite*)peep); - peep->var_6E = ebx; + peep->action_sprite_type = ebx; uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2]; - peep->var_14 = edx[ebx * 4]; - peep->var_09 = edx[ebx * 4 + 1]; - peep->var_15 = edx[ebx * 4 + 2]; + peep->sprite_width = edx[ebx * 4]; + peep->sprite_height_negative = edx[ebx * 4 + 1]; + peep->sprite_height_positive = edx[ebx * 4 + 2]; // This is pointless as nothing will have changed. invalidate_sprite((rct_sprite*)peep); } +/* 0x00693BE5 */ +static void sub_693BE5(rct_peep* peep, uint8 al){ + if (al == peep->var_6D)return; + + peep->var_6D = al; + + // If NONE_1 or NONE_2 + if (peep->action >= PEEP_ACTION_NONE_1){ + peep->action_sprite_image_offset = 0; + } + sub_693B58(peep); +} + +/** +* +* rct2: 0x0069A512 +*/ +void remove_peep_from_ride(rct_peep* peep) +{ + if (peep->state == PEEP_STATE_QUEUING) { + remove_peep_from_queue(peep); + } + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_1; + peep_window_state_update(peep); + sub_693BE5(peep, 0); +} + static void peep_state_reset(rct_peep* peep){ peep_decrement_num_riders(peep); peep->state = PEEP_STATE_1; peep_window_state_update(peep); - RCT2_CALLPROC_X(0x00693BE5, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693BE5(peep, 0); +} + +/* rct2: 0x69C308 + * Check if lost. + */ +void peep_check_if_lost(rct_peep* peep){ + if (!(peep->flags & PEEP_FLAGS_LOST)){ + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_COUNT, uint16) < 2)return; + peep->flags ^= PEEP_FLAGS_21; + + if (!(peep->flags & PEEP_FLAGS_21)) return; + + peep->var_F4++; + if (peep->var_F4 != 254)return; + peep->var_F4 = 230; + } + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_LOST, 0xFF); + + peep->happiness_growth_rate = max(peep->happiness_growth_rate - 30, 0); +} + +/* rct2: 0x69C26B +* Check if cant find ride. +*/ +void peep_check_cant_find_ride(rct_peep* peep){ + if (peep->guest_heading_to_ride_id == 0xFF) return; + + if (peep->var_C6 == 30 || peep->var_C6 == 60){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_FIND, peep->guest_heading_to_ride_id); + + peep->happiness_growth_rate = max(peep->happiness_growth_rate - 30, 0); + } + + peep->var_C6--; + if (peep->var_C6 != 0)return; + + peep->guest_heading_to_ride_id = 0xFF; + rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index); + + if (w){ + window_event_invalidate_call(w); + } + + widget_invalidate_by_number(WC_PEEP, peep->sprite_index, 12); +} + +/* rct2: 0x69C2D0 +* Check if cant find exit. +*/ +void peep_check_cant_find_exit(rct_peep* peep){ + if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK))return; + + if (peep->var_C6 == 1){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_FIND_EXIT, 0xFF); + + peep->happiness_growth_rate = max(peep->happiness_growth_rate - 30, 0); + } + + if (--peep->var_C6 == 0) peep->var_C6 = 90; } /* rct2: 0x6939EB - * Possibly peep update action frame. * Also used to move peeps to the correct position to - * start an action. Returns 0 if the correct destination - * has not yet been reached. + * start an action. Returns 1 if the correct destination + * has not yet been reached. xy_distance is how close the + * peep is to the target. */ -int sub_6939EB(sint16* x, sint16* y, rct_peep* peep){ - RCT2_GLOBAL(0xF1AEF0, uint8) = peep->var_70; +int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep){ + RCT2_GLOBAL(0xF1AEF0, uint8) = peep->action_sprite_image_offset; if (peep->action == 0xFE){ peep->action = 0xFF; } @@ -180,9 +274,11 @@ int sub_6939EB(sint16* x, sint16* y, rct_peep* peep){ int x_delta = abs(*x); int y_delta = abs(*y); - + + *xy_distance = x_delta + y_delta; + if (peep->action >= 0xFE){ - if (x_delta + y_delta <= peep->destination_tolerence){ + if (*xy_distance <= peep->destination_tolerence){ return 0; } int direction = 0; @@ -201,25 +297,24 @@ int sub_6939EB(sint16* x, sint16* y, rct_peep* peep){ peep->sprite_direction = direction; *x = peep->x + RCT2_ADDRESS(0x981D7C, uint16)[direction / 4]; *y = peep->y + RCT2_ADDRESS(0x981D7E, uint16)[direction / 4]; - int ebx = peep->var_E0 + 1; + peep->no_action_frame_no++; uint32* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]; - uint8* _edi = (uint8*)(edi[peep->var_6E * 2 + 1]); - if (ebx >= *_edi){ - ebx = 0; + uint8* _edi = (uint8*)(edi[peep->action_sprite_type * 2 + 1]); + if (peep->no_action_frame_no >= *_edi){ + peep->no_action_frame_no = 0; } - peep->var_E0 = ebx; - peep->var_70 = _edi[ebx + 1]; + peep->action_sprite_image_offset = _edi[peep->no_action_frame_no + 1]; return 1; } - int* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]; - uint8* _edi = (uint8*)(edi[peep->var_6E * 2 + 1]); + uint32* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]; + uint8* _edi = (uint8*)(edi[peep->action_sprite_type * 2 + 1]); peep->action_frame++; int ebx = _edi[peep->action_frame + 1]; // If last frame of action if (ebx == 0xFF){ - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; peep->action = 0xFF; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); @@ -227,7 +322,7 @@ int sub_6939EB(sint16* x, sint16* y, rct_peep* peep){ *y = peep->y; return 1; } - peep->var_70 = ebx; + peep->action_sprite_image_offset = ebx; // If not throwing up and not at the frame where sick appears. if (peep->action != PEEP_ACTION_THROW_UP || peep->action_frame != 15){ @@ -260,6 +355,7 @@ int sub_6939EB(sint16* x, sint16* y, rct_peep* peep){ *y = peep->y; return 1; } + /** * rct2: 0x0069A409 * Decreases rider count if on/entering a ride. @@ -270,10 +366,175 @@ void peep_decrement_num_riders(rct_peep* peep){ rct_ride* ride = GET_RIDE(peep->current_ride); ride->num_riders--; - ride->var_14D |= 0xC; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; } } +/* Part of 0x0069B8CC rct2:0x0069BC31 */ +void set_sprite_type(rct_peep* peep, uint8 type){ + if (peep->sprite_type == type)return; + + peep->sprite_type = type; + peep->action_sprite_image_offset = 0; + peep->no_action_frame_no = 0; + + if (peep->action >= PEEP_ACTION_NONE_1) + peep->action = PEEP_ACTION_NONE_2; + + peep->flags &= ~PEEP_FLAGS_SLOW_WALK; + if (RCT2_ADDRESS(0x00982134, uint8)[type] & 1){ + peep->flags |= PEEP_FLAGS_SLOW_WALK; + } + + peep->action_sprite_type = 0xFF; + sub_693B58(peep); + + if (peep->state == PEEP_STATE_SITTING){ + peep->action = PEEP_ACTION_NONE_1; + peep->var_6F = 7; + sub_693BAB(peep); + } + if (peep->state == PEEP_STATE_WATCHING){ + peep->action = PEEP_ACTION_NONE_1; + peep->var_6F = 2; + sub_693BAB(peep); + } +} + +typedef struct{ + uint8 type; // 0 for standard, 1 for extra + uint32 item; // And this with the relevant flags + uint8 sprite_type; +} item_pref; + +item_pref item_order_preference[] = { + { 0, PEEP_ITEM_ICE_CREAM, 15 }, + { 0, PEEP_ITEM_FRIES, 16}, + { 0, PEEP_ITEM_PIZZA, 22 }, + { 0, PEEP_ITEM_BURGER, 17 }, + { 0, PEEP_ITEM_DRINK, 18 }, + { 0, PEEP_ITEM_COFFEE, 35 }, + { 0, PEEP_ITEM_CHICKEN, 34 }, + { 0, PEEP_ITEM_LEMONADE, 37 }, + { 0, PEEP_ITEM_COTTON_CANDY, 20 }, + { 0, PEEP_ITEM_POPCORN, 22 }, + { 0, PEEP_ITEM_HOT_DOG, 31 }, + { 0, PEEP_ITEM_TENTACLE, 32 }, + { 0, PEEP_ITEM_CANDY_APPLE, 33 }, + { 0, PEEP_ITEM_DONUT, 34 }, + { 1, PEEP_ITEM_PRETZEL, 39 }, + { 1, PEEP_ITEM_COOKIE, 39 }, + { 1, PEEP_ITEM_CHOCOLATE, 35 }, + { 1, PEEP_ITEM_ICED_TEA, 35 }, + { 1, PEEP_ITEM_FUNNEL_CAKE, 43 }, + { 1, PEEP_ITEM_BEEF_NOODLES, 44 }, + { 1, PEEP_ITEM_FRIED_RICE_NOODLES, 44 }, + { 1, PEEP_ITEM_WONTON_SOUP, 46 }, + { 1, PEEP_ITEM_MEATBALL_SOUP, 46 }, + { 1, PEEP_ITEM_FRUIT_JUICE, 43 }, + { 1, PEEP_ITEM_SOYBEAN_MILK, 41 }, + { 1, PEEP_ITEM_SU_JONGKWA, 41 }, + { 1, PEEP_ITEM_SUB_SANDWICH, 47 }, + { 1, PEEP_ITEM_ROAST_SAUSAGE, 45 }, + { 0, PEEP_ITEM_BALLOON, 19 }, + { 0, PEEP_ITEM_HAT, 30}, + { 1, PEEP_ITEM_SUNGLASSES, 40}, + { 0xFF, 0xFFFFFFFF, 0xFF} +}; + +/* rct2: 0x0069B8CC */ +void peep_update_sprite_type(rct_peep* peep){ + if (peep->sprite_type == 19 && + (scenario_rand() & 0xFFFF) <= 327){ + uint8 bl = 0; + + if ((scenario_rand() & 0xFFFF) <= 13107 && + peep->x != SPRITE_LOCATION_NULL){ + + bl = 1; + sound_play_panned(SOUND_BALLOON_POP, 0x8001, peep->x, peep->y, peep->z); + } + + if (peep->x != SPRITE_LOCATION_NULL){ + create_balloon(peep->x, peep->y, peep->z + 9, peep->balloon_colour, bl); + } + + peep->item_standard_flags &= ~PEEP_ITEM_BALLOON; + + peep->var_45 |= (1 << 3); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8) != 0 && + peep->item_standard_flags & PEEP_ITEM_UMBRELLA && + peep->x != SPRITE_LOCATION_NULL){ + int x = peep->x & 0xFFE0; + int y = peep->y & 0xFFE0; + + if (x < 0x1FFF && y < 0x1FFF){ + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while (1) { + if ((peep->z / 32) < map_element->base_height)break; + + if (map_element_is_last_for_tile(map_element)){ + set_sprite_type(peep, 21); + return; + } + map_element++; + } + } + } + + for (item_pref* item_pref = item_order_preference; item_pref->type != 0xFF; item_pref++){ + if (item_pref->type == 0){ + if (peep->item_standard_flags & item_pref->item){ + set_sprite_type(peep, item_pref->sprite_type); + return; + } + } + else{ + if (peep->item_extra_flags & item_pref->item){ + set_sprite_type(peep, item_pref->sprite_type); + return; + } + } + } + + if (peep->state == PEEP_STATE_WATCHING && + peep->standing_flags & (1<<1)){ + set_sprite_type(peep, 38); + return; + } + + if (peep->nausea > 170){ + set_sprite_type(peep, 28); + return; + } + + if (peep->nausea > 140){ + set_sprite_type(peep, 27); + return; + } + + if (peep->energy <= 64 && + peep->happiness < 128){ + set_sprite_type(peep, 26); + return; + } + + if (peep->energy <= 80 && + peep->happiness < 128){ + set_sprite_type(peep, 25); + return; + } + + if (peep->bathroom > 220){ + set_sprite_type(peep, 29); + return; + } + + set_sprite_type(peep, 0); +} + /** * rct2: 0x0069A42F * Call after changing a peeps state to insure that @@ -283,9 +544,8 @@ void peep_decrement_num_riders(rct_peep* peep){ void peep_window_state_update(rct_peep* peep){ rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index); - if (w){ - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); - } + if (w != NULL) + window_event_invalidate_call(w); if (peep->type == PEEP_TYPE_GUEST){ // Update action label @@ -294,7 +554,7 @@ void peep_window_state_update(rct_peep* peep){ if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE){ rct_ride* ride = GET_RIDE(peep->current_ride); ride->num_riders++; - ride->var_14D |= 0xC; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; } window_invalidate_by_class(WC_GUEST_LIST); @@ -306,6 +566,33 @@ void peep_window_state_update(rct_peep* peep){ } } +/* rct2: 0x0069A535*/ +void peep_sprite_remove(rct_peep* peep){ + remove_peep_from_ride(peep); + invalidate_sprite((rct_sprite*)peep); + + window_close_by_number(WC_PEEP, peep->sprite_index); + + window_close_by_number(WC_FIRE_PROMPT, peep->sprite_identifier); + + if (peep->type == PEEP_TYPE_GUEST){ + window_invalidate_by_class(WC_GUEST_LIST); + + news_item_disable_news(NEWS_ITEM_PEEP_ON_RIDE, peep->sprite_index); + } + else{ + window_invalidate_by_class(WC_STAFF_LIST); + + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] = 0; + peep->type = 0xFF; + staff_update_greyed_patrol_areas(); + peep->type = PEEP_TYPE_STAFF; + + news_item_disable_news(NEWS_ITEM_PEEP, peep->sprite_index); + } + sprite_remove((rct_sprite*)peep); +} + /** New function removes peep from * park existance. Works with staff. */ @@ -313,13 +600,13 @@ void peep_remove(rct_peep* peep){ if (peep->type == PEEP_TYPE_GUEST){ if (peep->var_2A == 0){ RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)--; - RCT2_GLOBAL(0x9A9804, uint16) |= (1 << 2); + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT; } if (peep->state == PEEP_STATE_ENTERING_PARK){ RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; } } - RCT2_CALLPROC_X(0x69A535, 0, 0, 0, 0, (int)peep, 0, 0); + peep_sprite_remove(peep); } /** @@ -329,9 +616,9 @@ void peep_remove(rct_peep* peep){ void peep_update_falling(rct_peep* peep){ if (peep->action == PEEP_ACTION_DROWNING){ // Check to see if we are ready to drown. - sint16 x, y; - sub_6939EB(&x, &y, peep); - //RCT2_CALLPROC_X(0x6939EB, 0, 0, 0, 0, (int)peep, 0, 0); + sint16 x, y, xy_distance; + + peep_update_action(&x, &y, &xy_distance, peep); if (peep->action == PEEP_ACTION_DROWNING) return; if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x80000)){ RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; @@ -347,26 +634,23 @@ void peep_update_falling(rct_peep* peep){ } // If not drowning then falling. Note: peeps 'fall' after leaving a ride/enter the park. - - rct_map_element *map_element = TILE_MAP_ELEMENT_POINTER((peep->y / 32) * 256 + (peep->x /32)); + rct_map_element *map_element = map_get_first_element_at(peep->x / 32, peep->y / 32); rct_map_element *saved_map = NULL; int saved_height = 0; - for (int final_element = 0; !final_element; map_element++){ - final_element = map_element->flags & MAP_ELEMENT_FLAG_LAST_TILE; - + do { // If a path check if we are on it - if (map_element->type == MAP_ELEMENT_TYPE_PATH){ + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){ int height = map_height_from_slope(peep->x, peep->y, map_element->properties.surface.slope) + map_element->base_height * 8; - if (height < peep->z - 1 || height - 4 > peep->z) continue; + if (height < peep->z - 1 || height > peep->z + 4) continue; saved_height = height; saved_map = map_element; break; } // If a surface get the height and see if we are on it - else if (map_element->type == MAP_ELEMENT_TYPE_SURFACE){ + else if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_SURFACE){ // If the surface is water check to see if we could be drowning if (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){ int height = (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) * 16; @@ -379,10 +663,10 @@ void peep_update_falling(rct_peep* peep){ if (peep->item_standard_flags & PEEP_ITEM_BALLOON){ peep->item_standard_flags &= ~PEEP_ITEM_BALLOON; - if (peep->sprite_type == 19 && peep->x != 0x8000){ - create_balloon(peep->x, peep->y, height, peep->balloon_colour); + if (peep->sprite_type == 19 && peep->x != (sint16)0x8000){ + create_balloon(peep->x, peep->y, height, peep->balloon_colour, 0); peep->var_45 |= (1 << 3); - RCT2_CALLPROC_X(0x0069B8CC, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_sprite_type(peep); } } @@ -390,7 +674,7 @@ void peep_update_falling(rct_peep* peep){ peep->action = PEEP_ACTION_DROWNING; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); @@ -404,7 +688,7 @@ void peep_update_falling(rct_peep* peep){ saved_map = map_element; } // If not a path or surface go see next element else continue; - } + } while (!map_element_is_last_for_tile(map_element++)); // This will be null if peep is falling if (saved_map == NULL){ @@ -428,10 +712,10 @@ void peep_update_falling(rct_peep* peep){ peep->next_z = saved_map->base_height; int edx = saved_map->properties.surface.slope & 0x7; - if (saved_map->type != MAP_ELEMENT_TYPE_PATH){ + if (map_element_get_type(saved_map) != MAP_ELEMENT_TYPE_PATH){ edx = 8; } - peep->next_z += edx << 8; + peep->next_var_29 = edx; peep_decrement_num_riders(peep); peep->state = PEEP_STATE_1; peep_window_state_update(peep); @@ -462,7 +746,7 @@ void peep_try_get_up_from_sitting(rct_peep* peep){ * rct2: 0x0069152B */ void peep_update_sitting(rct_peep* peep){ - if (peep->var_2C == 0){ + if (peep->sub_state == 0){ if (!sub_68F3AE(peep))return; //691541 @@ -481,18 +765,17 @@ void peep_update_sitting(rct_peep* peep){ invalidate_sprite((rct_sprite*)peep); peep->action = 254; peep->var_6F = 7; - RCT2_CALLPROC_X(0x693BAB, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693BAB(peep); - peep->var_2C++; + peep->sub_state++; // Sets time to sit on seat peep->time_to_sitdown = (129 - peep->energy) * 16 + 50; } - else if (peep->var_2C == 1){ + else if (peep->sub_state == 1){ if (peep->action < 0xFE){ - sint16 x, y; - sub_6939EB(&x, &y, peep); - //RCT2_CALLPROC_X(0x6939EB, 0, 0, 0, 0, (int)peep, 0, 0); + sint16 x, y, xy_distance; + peep_update_action(&x, &y, &xy_distance, peep); if (peep->action != 0xFF) return; peep->action = 0xFE; @@ -525,7 +808,7 @@ void peep_update_sitting(rct_peep* peep){ } peep->action = PEEP_ACTION_SITTING_EAT_FOOD; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); return; @@ -550,17 +833,1788 @@ void peep_update_sitting(rct_peep* peep){ peep->action = PEEP_ACTION_SITTING_CHECK_WATCH; } peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); return; } } +/** + * + * rct2: 0x006966A9 + */ +void remove_peep_from_queue(rct_peep* peep) +{ + rct_ride* ride = GET_RIDE(peep->current_ride); + + uint8 cur_station = peep->current_ride_station; + ride->queue_length[cur_station]--; + if (peep->sprite_index == ride->first_peep_in_queue[cur_station]) + { + ride->first_peep_in_queue[cur_station] = peep->next_in_queue; + return; + } + + for (rct_peep* other_peep = GET_PEEP(ride->first_peep_in_queue[cur_station]);; + other_peep = GET_PEEP(other_peep->next_in_queue)){ + if (peep->sprite_index == other_peep->next_in_queue){ + other_peep->next_in_queue = peep->next_in_queue; + return; + } + } +} + +/* rct2: 0x00691C6E */ +static rct_vehicle* peep_choose_car_from_ride(rct_peep* peep, rct_ride* ride, uint8* car_array, uint8 car_array_size){ + uint8 chosen_car = scenario_rand(); + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_HAS_G_FORCES + && ((chosen_car & 0xC) != 0xC)){ + chosen_car = (scenario_rand() & 1) ? 0 : car_array_size - 1; + } + else{ + chosen_car = (chosen_car * (uint16)car_array_size) >> 8; + } + + peep->current_car = car_array[chosen_car]; + + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + + for (int i = peep->current_car; i > 0; --i){ + vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train); + } + + return vehicle; +} + +/* rct2: 0x00691CD1 */ +static void peep_choose_seat_from_car(rct_peep* peep, rct_ride* ride, rct_vehicle* vehicle){ + uint8 chosen_seat = vehicle->next_free_seat; + + if (ride->mode == RIDE_MODE_FORWARD_ROTATION || + ride->mode == RIDE_MODE_BACKWARD_ROTATION){ + + chosen_seat = (((~vehicle->var_1F + 1) >> 3) & 0xF) * 2; + if (vehicle->next_free_seat & 1){ + chosen_seat++; + } + } + peep->current_seat = chosen_seat; + vehicle->next_free_seat++; + + vehicle->peep[peep->current_seat] = peep->sprite_index; + vehicle->peep_tshirt_colours[peep->current_seat] = peep->tshirt_colour; +} + +/* rct2: 0x00691D27 */ +static void peep_go_to_ride_entrance(rct_peep* peep, rct_ride* ride){ + int x = ride->entrances[peep->current_ride_station] & 0xFF; + int y = ride->entrances[peep->current_ride_station] >> 8; + int z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 direction = !map_element ? 0 : map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + x *= 32; + y *= 32; + x += 16; + y += 16; + + sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2]; + sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2]; + + uint8 shift_multiplier = 21; + rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype); + if (ride_type->vehicles[ride_type->default_vehicle].var_12 & (1 << 3) || + ride_type->vehicles[ride_type->default_vehicle].var_14 & 0x5000){ + shift_multiplier = 32; + } + + x_shift *= shift_multiplier; + y_shift *= shift_multiplier; + + x += x_shift; + y += y_shift; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 2; + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_ENTERING_RIDE; + peep->sub_state = 1; + peep_window_state_update(peep); + + peep->var_AC = 0; + peep->var_E2 = 0; + + remove_peep_from_queue(peep); +} + +/* rct2: 0x00691A3B */ +static void peep_update_ride_sub_state_0(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (peep->destination_tolerence != 0){ + invalidate_sprite((rct_sprite*)peep); + + sint16 x, y, xy_distance; + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + sint16 z = peep->z; + if (xy_distance < 16){ + z = ride->station_heights[peep->current_ride_station] * 8 + 2; + } + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + } + else{ + peep->destination_tolerence = 0; + peep->sprite_direction ^= (1 << 4); + } + } + + uint8 car_array_size = 0xFF; + uint8* car_array = RCT2_ADDRESS(0xF1AD78, uint8); + + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_13){ + if (ride->num_riders >= ride->operation_option) + return; + } + else{ + uint8 chosen_train = 0xFF; + + if (ride->mode == RIDE_MODE_BUMPERCAR || ride->mode == RIDE_MODE_RACE){ + if (ride->lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING) + return; + + for (int i = 0; i < ride->num_vehicles; ++i){ + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[i]); + + if (vehicle->next_free_seat >= vehicle->num_seats) + continue; + + if (vehicle->status != VEHICLE_STATUS_WAITING_FOR_PASSENGERS) + continue; + chosen_train = i; + break; + } + } + else{ + chosen_train = ride->var_066[peep->current_ride_station]; + } + if (chosen_train == 0xFF){ + return; + } + + peep->current_train = chosen_train; + uint8* car_array_pointer = car_array; + + int i = 0; + + uint16 vehicle_id = ride->vehicles[chosen_train]; + rct_vehicle* vehicle = GET_VEHICLE(vehicle_id); + + for (; vehicle_id != 0xFFFF; + vehicle_id = vehicle->next_vehicle_on_train, + i++){ + vehicle = GET_VEHICLE(vehicle_id); + + uint8 num_seats = vehicle->num_seats; + if (vehicle_is_used_in_pairs(vehicle)){ + num_seats &= VEHICLE_SEAT_NUM_MASK; + if (vehicle->next_free_seat & 1){ + peep->current_car = i; + peep_choose_seat_from_car(peep, ride, vehicle); + peep_go_to_ride_entrance(peep, ride); + return; + } + } + if (num_seats == vehicle->next_free_seat) + continue; + + if (ride->mode == RIDE_MODE_FORWARD_ROTATION || + ride->mode == RIDE_MODE_BACKWARD_ROTATION) + { + uint8 position = (((~vehicle->var_1F + 1) >> 3) & 0xF) * 2; + if (vehicle->peep[position] != 0xFFFF) + continue; + } + + *car_array_pointer++ = i; + } + + car_array_size = car_array_pointer - car_array; + + if (car_array_size == 0)return; + } + + if (ride->status != RIDE_STATUS_OPEN || + ride->var_1CA != 0){ + if (peep->destination_tolerence == 0){ + remove_peep_from_queue(peep); + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + } + return; + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) + return; + + if (ride->price != 0){ + if (!(peep->item_standard_flags & PEEP_ITEM_VOUCHER) || + !(peep->voucher_type == VOUCHER_TYPE_RIDE_FREE) || + !(peep->voucher_arguments == peep->current_ride)){ + + if (peep->cash_in_pocket <= 0){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SPENT_MONEY, 0xFF); + if (peep->destination_tolerence == 0){ + remove_peep_from_queue(peep); + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + } + return; + } + + if (ride->price > peep->cash_in_pocket){ + peep_insert_new_thought(peep, 0, peep->current_ride); + if (peep->destination_tolerence == 0){ + remove_peep_from_queue(peep); + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + } + return; + } + + uint16 value = ride->value; + if (value != RIDE_VALUE_UNDEFINED){ + if (value * 2 < ride->price){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_BAD_VALUE, peep->current_ride); + if (peep->destination_tolerence == 0){ + remove_peep_from_queue(peep); + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + } + return; + } + } + } + } + + if (!(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_13)){ + rct_vehicle* vehicle = peep_choose_car_from_ride(peep, ride, car_array, car_array_size); + peep_choose_seat_from_car(peep, ride, vehicle); + } + peep_go_to_ride_entrance(peep, ride); +} + +/* rct2: 0x006921D3 */ +void peep_update_ride_sub_state_1(rct_peep* peep){ + sint16 x, y, xy_distance; + + rct_ride* ride = GET_RIDE(peep->current_ride); + rct_ride_type* ride_entry = gRideTypeList[ride->subtype]; + + if (peep_update_action(&x, &y, &xy_distance, peep)) + { + uint8 vehicle = ride_entry->default_vehicle; + + if (ride_entry->vehicles[vehicle].var_12 & (1 << 3) || + ride_entry->vehicles[vehicle].var_14 & ((1 << 14) | (1<<12))) + RCT2_GLOBAL(0xF1AECA, uint16) = 0x1C; + else + RCT2_GLOBAL(0xF1AECA, uint16) = 0x10; + + if (peep->sub_state == 1 && + xy_distance < RCT2_GLOBAL(0xF1AECA, uint16)) + peep->sub_state = 2; + + invalidate_sprite((rct_sprite*)peep); + + sint16 z = ride->station_heights[peep->current_ride_station] * 8; + + RCT2_GLOBAL(0xF1AECA, uint16) += 4; + + if (xy_distance < RCT2_GLOBAL(0xF1AECA, uint16)){ + z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8]; + } + + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] &RIDE_TYPE_FLAG_13) + { + sint16 x, y, z; + x = ride->entrances[peep->current_ride_station] & 0xFF; + y = ride->entrances[peep->current_ride_station] >> 8; + z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 direction_entrance = (map_element->type & MAP_ELEMENT_DIRECTION_MASK); + + if (ride->type == RIDE_TYPE_MAZE){ + peep->maze_last_edge = direction_entrance + 1; + x *= 32; + y *= 32; + + x += RCT2_ADDRESS(0x993CCC, sint16)[direction_entrance * 2]; + y += RCT2_ADDRESS(0x993CCE, sint16)[direction_entrance * 2]; + + uint8 direction = direction_entrance * 4 + 11; + if (scenario_rand() & 0x40){ + direction += 4; + peep->maze_last_edge += 2; + } + + direction &= 0xF; + peep->var_37 = direction; + peep->maze_last_edge &= 3; + + x += RCT2_GLOBAL(0x981FD1 + direction, sint16); + y += RCT2_GLOBAL(0x981FD3 + direction, sint16); + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 3; + + ride->var_120++; + RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0); + peep->sub_state = 17; + return; + } + + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + map_element = ride_get_station_start_track_element(ride, peep->current_ride_station); + + uint8 direction_track = (!map_element ? 0 : map_element->type & MAP_ELEMENT_DIRECTION_MASK); + + peep->var_37 = (direction_entrance << 2) | (direction_track << 4); + + x *= 32; + y *= 32; + + sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type]; + + x += edx[0]; + y += edx[1]; + + peep->destination_x = x; + peep->destination_y = y; + peep->current_car = 0; + + ride->var_120++; + RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0); + peep->sub_state = 14; + return; + } + + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + for (int i = peep->current_car; i != 0; --i){ + vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train); + } + + ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype); + rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type]; + + if (vehicle_type->var_14 & (1 << 10)){ + sint16 x, y, z; + x = ride->entrances[peep->current_ride_station] & 0xFF; + y = ride->entrances[peep->current_ride_station] >> 8; + z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 direction_entrance = !map_element ? 0 : map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + map_element = ride_get_station_start_track_element(ride, peep->current_ride_station); + + uint8 direction_track = (!map_element ? 0 : map_element->type & MAP_ELEMENT_DIRECTION_MASK); + + vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype); + vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type]; + + uint8 cl = peep->current_seat; + uint8 ch = peep->current_seat & 0xF8; + + if (ride->type != RIDE_TYPE_ENTERPRISE) + direction_track *= 2; + + if (*vehicle_type->peep_loading_positions == 0){ + direction_track /= 2; + cl = 0; + ch = 0; + } + cl += direction_track; + cl &= 0x7; + cl += ch; + peep->var_37 = (direction_entrance | cl * 4) * 4; + + x *= 32; + y *= 32; + x += 16; + y += 16; + + if (ride->type == RIDE_TYPE_ENTERPRISE) + { + x = vehicle->x; + y = vehicle->y; + } + + x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1]; + y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2]; + + peep->destination_x = x; + peep->destination_y = y; + peep->sub_state = 12; + return; + } + + if (vehicle_type->var_14 & (1 << 15)){ + peep->destination_x = vehicle->x; + peep->destination_y = vehicle->y; + peep->destination_tolerence = 15; + peep->sub_state = 4; + return; + } + + sint8 load_position = vehicle_type->peep_loading_positions[peep->current_seat]; + + switch (vehicle->sprite_direction / 8){ + case 0: + peep->destination_x = vehicle->x - load_position; + break; + case 1: + peep->destination_y = vehicle->y + load_position; + break; + case 2: + peep->destination_x = vehicle->x + load_position; + break; + case 3: + peep->destination_y = vehicle->y - load_position; + break; + } + + peep->sub_state = 4; + return; +} + +/* rct2: 0x0069321D */ +static void peep_go_to_ride_exit(rct_peep* peep, rct_ride* ride, sint16 x, sint16 y, sint16 z, uint8 exit_direction){ + z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8]; + + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + + x = ride->exits[peep->current_ride_station] & 0xFF; + y = ride->exits[peep->current_ride_station] >> 8; + x *= 32; + y *= 32; + x += 16; + y += 16; + + sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2]; + sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2]; + + sint16 shift_multiplier = 20; + + rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype); + rct_ride_type_vehicle* vehicle_entry = &ride_type->vehicles[ride_type->default_vehicle]; + if (vehicle_entry->var_12 & (1 << 3) || + vehicle_entry->var_14 & 0x5000){ + shift_multiplier = 32; + } + + x_shift *= shift_multiplier; + y_shift *= shift_multiplier; + + x -= x_shift; + y -= y_shift; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 2; + + peep->sprite_direction = exit_direction * 8; + peep->sub_state = 8; + return; +} + +/* rct2: 0x006920B4 */ +static void peep_update_ride_sub_state_2_enter_ride(rct_peep* peep, rct_ride* ride){ + if (ride->price != 0){ + if ((peep->item_standard_flags & PEEP_ITEM_VOUCHER) && + (peep->voucher_type == VOUCHER_TYPE_RIDE_FREE) && + (peep->voucher_arguments == peep->current_ride)){ + + peep->item_standard_flags &= ~PEEP_ITEM_VOUCHER; + peep->var_45 |= (1 << 3); + } + else{ + ride->total_profit += ride->price; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 20; + RCT2_GLOBAL(0xF1AEC0, uint32) = 230; + + RCT2_CALLPROC_X(0x0069926C, 0, ride->price, 0, 0, (int)peep, 0, 0); + } + } + + peep->sub_state++; + uint8 queue_time = peep->days_in_queue; + if (queue_time < 253)queue_time += 3; + + queue_time /= 2; + if (queue_time != ride->queue_time[peep->current_ride_station]){ + ride->queue_time[peep->current_ride_station] = queue_time; + window_invalidate_by_number(WC_RIDE, peep->current_ride); + } + + if (peep->flags & PEEP_FLAGS_TRACKING){ + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954, uint32) = peep->id; + RCT2_GLOBAL(0x13CE958, uint16) = ride->name; + RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments; + + rct_string_id msg_string; + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_IN_RIDE) + msg_string = 1932; + else + msg_string = 1933; + + news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, msg_string, peep->sprite_index); + } + + if (ride->type == RIDE_TYPE_SPIRAL_SLIDE){ + sub_693BE5(peep, 1); + } + + peep_update_ride_sub_state_1(peep); +} + +/* rct2: 0x00691FD4 */ +static void peep_update_ride_sub_state_2_rejoin_queue(rct_peep* peep, rct_ride* ride){ + sint16 x, y, z; + x = ride->entrances[peep->current_ride_station] & 0xFF; + y = ride->entrances[peep->current_ride_station] >> 8; + z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 direction_entrance = !map_element ? 0 : map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + x *= 32; + y *= 32; + x += 16 - RCT2_ADDRESS(0x981D6C, sint16)[direction_entrance * 2] * 20; + y += 16 - RCT2_ADDRESS(0x981D6E, sint16)[direction_entrance * 2] * 20; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 2; + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_QUEUING_FRONT; + peep->sub_state = 0; + peep_window_state_update(peep); + + peep->next_in_queue = 0xFFFF; + + ride->queue_length[peep->current_ride_station]++; + + uint16 current_first = ride->first_peep_in_queue[peep->current_ride_station]; + if (current_first == 0xFFFF){ + ride->first_peep_in_queue[peep->current_ride_station] = peep->sprite_index; + return; + } + + rct_peep* queue_peep; + for (queue_peep = GET_PEEP(current_first); + queue_peep->next_in_queue != 0xFFFF; + queue_peep = GET_PEEP(queue_peep->next_in_queue)); + + queue_peep->next_in_queue = peep->sprite_index; +} +/* rct2: 0x00691E42 + * Note: Before this was the entry + * point for sub state 1 and 3. The + * check has been removed that would + * branch it out to 1 and 3. Now uses + * separate functions. + */ +static void peep_update_ride_sub_state_2(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_13){ + if (ride->status != RIDE_STATUS_OPEN || + ride->var_1CA != 0 || + (++peep->var_AC) == 0){ + + peep_update_ride_sub_state_2_rejoin_queue(peep, ride); + return; + } + + peep_update_ride_sub_state_2_enter_ride(peep, ride); + return; + } + + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + for (int i = peep->current_car; i != 0; --i){ + vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train); + } + + rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype); + + if (ride_entry->vehicles[0].var_12 & (1 << 3)){ + vehicle->var_D5 &= ~(1 << 5); + + + for (int i = 0; i < ride->num_vehicles; ++i){ + if (ride->vehicles[i] == 0xFFFF) + continue; + + rct_vehicle* train = GET_VEHICLE(ride->vehicles[i]); + rct_vehicle* second_vehicle = GET_VEHICLE(train->next_vehicle_on_train); + + if (second_vehicle->num_peeps == 0) + continue; + + if (second_vehicle->var_D5 & (1 << 5)) + continue; + + return; + } + } + + if (!vehicle_is_used_in_pairs(vehicle)){ + peep_update_ride_sub_state_2_enter_ride(peep, ride); + return; + } + + if (ride->mode == RIDE_MODE_FORWARD_ROTATION || + ride->mode == RIDE_MODE_BACKWARD_ROTATION){ + if (peep->current_seat & 1 || + !(vehicle->next_free_seat & 1)){ + peep_update_ride_sub_state_2_enter_ride(peep, ride); + return; + } + } + else{ + uint8 current_seat = (peep->current_seat & 0xFE) + 1; + if (current_seat < vehicle->next_free_seat) + { + peep_update_ride_sub_state_2_enter_ride(peep, ride); + return; + } + } + + if (ride->status == RIDE_STATUS_OPEN && + ++peep->var_AC != 0 && + !((GET_VEHICLE(ride->vehicles[peep->current_train]))->var_48 & (1 << 4))) + return; + + if (ride->mode != RIDE_MODE_FORWARD_ROTATION && + ride->mode != RIDE_MODE_BACKWARD_ROTATION){ + if (vehicle->next_free_seat - 1 != peep->current_seat) + return; + } + + vehicle->next_free_seat--; + vehicle->peep[peep->current_seat] = 0xFFFF; + + peep_update_ride_sub_state_2_rejoin_queue(peep, ride); +} + +static void peep_update_ride_sub_state_5(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + for (int i = peep->current_car; i != 0; --i){ + vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train); + } + + if (ride->mode != RIDE_MODE_FORWARD_ROTATION && + ride->mode != RIDE_MODE_BACKWARD_ROTATION){ + if (peep->current_seat != vehicle->num_peeps) + return; + } + + if (vehicle_is_used_in_pairs(vehicle)){ + rct_peep* seated_peep = GET_PEEP(vehicle->peep[peep->current_seat ^ 1]); + if (seated_peep->sub_state != 5) + return; + + vehicle->num_peeps++; + ride->var_120++; + + vehicle->var_46 += seated_peep->var_41; + invalidate_sprite((rct_sprite*)seated_peep); + sprite_move(0x8000, 0, 0, (rct_sprite*)seated_peep); + + peep_decrement_num_riders(seated_peep); + seated_peep->state = PEEP_STATE_ON_RIDE; + peep_window_state_update(seated_peep); + seated_peep->var_E2 = 0; + seated_peep->sub_state = 6; + RCT2_CALLPROC_X(0x00695444, 0, 0, 0, seated_peep->current_ride, (int)seated_peep, 0, 0); + } + + vehicle->num_peeps++; + ride->var_120++; + + vehicle->var_46 += peep->var_41; + invalidate_sprite((rct_sprite*)vehicle); + + invalidate_sprite((rct_sprite*)peep); + sprite_move(0x8000, 0, 0, (rct_sprite*)peep); + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_ON_RIDE; + peep_window_state_update(peep); + + peep->var_E2 = 0; + peep->sub_state = 6; + + RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0); +} + +/* rct2: 0x00693028*/ +static void peep_update_ride_sub_state_7(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + uint8 ride_station = vehicle->current_station; + + for (int i = peep->current_car; i != 0; --i){ + vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train); + } + + // Unsure why backward rotation is missing. + if (ride->mode != RIDE_MODE_FORWARD_ROTATION){ + if (vehicle->num_peeps - 1 != peep->current_seat) + return; + } + + peep->action_sprite_image_offset++; + if (peep->action_sprite_image_offset & 3) + return; + + peep->action_sprite_image_offset = 0; + + vehicle->num_peeps--; + vehicle->var_46 -= peep->var_41; + invalidate_sprite((rct_sprite*)vehicle); + + peep->current_ride_station = ride_station; + + rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype); + rct_ride_type_vehicle* vehicle_entry = &ride_entry->vehicles[vehicle->vehicle_type]; + + if (!(vehicle_entry->var_14 & (1 << 10))){ + sint16 x, y, z; + x = ride->exits[peep->current_ride_station] & 0xFF; + y = ride->exits[peep->current_ride_station] >> 8; + z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + exit_direction ^= (1 << 1); + + if (!(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_16)){ + + for (; vehicle->var_01 != 0; vehicle = GET_VEHICLE(vehicle->prev_vehicle_on_train)){ + uint16 eax = vehicle->var_36 / 4; + if (eax == 0 || eax > 3) + continue; + + rct_map_element* inner_map = map_get_first_element_at(vehicle->var_38 / 32, vehicle->var_3A / 32); + for (;; inner_map++){ + if (map_element_get_type(inner_map) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (inner_map->base_height == vehicle->var_3C / 8) + break; + } + + uint8 al = (inner_map->properties.track.sequence & 0x70) >> 4; + if (al == peep->current_ride_station) + break; + } + + ride_entry = GET_RIDE_ENTRY(ride->subtype); + vehicle_entry = &ride_entry->vehicles[ride_entry->default_vehicle]; + + uint8 shift_multiplier = 12; + if (vehicle_entry->var_14 & (1 << 14)){ + shift_multiplier = 9; + } + + uint8 direction = exit_direction; + if (vehicle_entry->var_14 & ((1 << 14) | (1 << 12))){ + direction = ((vehicle->sprite_direction + 3) / 8) + 1; + direction &= 3; + + if (vehicle->var_CD == 6) + direction ^= (1 << 1); + } + + sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2]; + sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2]; + + x = vehicle->x + x_shift * shift_multiplier; + y = vehicle->y + y_shift * shift_multiplier; + z *= 8; + + peep_go_to_ride_exit(peep, ride, x, y, z, exit_direction); + return; + } + + x = vehicle->x + RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2] * 12; + y = vehicle->y + RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2] * 12; + + sint8 load_position = vehicle_entry->peep_loading_positions[peep->current_seat]; + + switch (vehicle->sprite_direction / 8){ + case 0: + x -= load_position; + break; + case 1: + y += load_position; + break; + case 2: + x += load_position; + break; + case 3: + y -= load_position; + break; + } + + z = ride->station_heights[peep->current_ride_station] * 8; + + peep_go_to_ride_exit(peep, ride, x, y, z, exit_direction); + return; + } + + sint16 x, y, z; + x = ride->exits[peep->current_ride_station] & 0xFF; + y = ride->exits[peep->current_ride_station] >> 8; + z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + map_element = ride_get_station_start_track_element(ride, peep->current_ride_station); + + uint8 station_direction = (!map_element ? 0 : map_element->type & MAP_ELEMENT_DIRECTION_MASK); + + vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + + ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype); + rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type]; + + uint8 cl = peep->current_seat; + uint8 ch = peep->current_seat & 0xF8; + + if (ride->type != RIDE_TYPE_ENTERPRISE) + station_direction *= 2; + + if (*vehicle_type->peep_loading_positions == 0){ + station_direction /= 2; + cl = 0; + ch = 0; + } + cl += station_direction; + cl &= 0x7; + cl += ch; + peep->var_37 = ((exit_direction | cl * 4) * 4) | 1; + + x *= 32; + y *= 32; + x += 16; + y += 16; + + if (ride->type == RIDE_TYPE_ENTERPRISE) + { + x = vehicle->x; + y = vehicle->y; + } + + sint16 exit_x = x + vehicle_type->peep_loading_positions[(peep->var_37 + 1) * 2 + 1]; + sint16 exit_y = y + vehicle_type->peep_loading_positions[(peep->var_37 + 1) * 2 + 2]; + + z *= 8; + z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8]; + + if (ride->type == RIDE_TYPE_MOTION_SIMULATOR) + z += 15; + + sprite_move(exit_x, exit_y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + + x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1]; + y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2]; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 2; + peep->sub_state = 13; +} + +/* rct2: 0x0069376A */ +static void peep_update_ride_prepare_for_state_9(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + sint16 x = ride->exits[peep->current_ride_station] & 0xFF; + sint16 y = ride->exits[peep->current_ride_station] >> 8; + sint16 z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + x *= 32; + y *= 32; + x += 16; + y += 16; + + sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2]; + sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2]; + + sint16 shift_multiplier = 20; + + rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype); + rct_ride_type_vehicle* vehicle_entry = &ride_type->vehicles[ride_type->default_vehicle]; + if (vehicle_entry->var_14 & 0x5000){ + shift_multiplier = 32; + } + + x_shift *= shift_multiplier; + y_shift *= shift_multiplier; + + x -= x_shift; + y -= y_shift; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 2; + peep->sub_state = 9; +} + +/* rct2: 0x0069374F */ +static void peep_update_ride_sub_state_8(rct_peep* peep){ + sint16 x, y, xy_distance; + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + peep_update_ride_prepare_for_state_9(peep); +} + +/* rct2: 0x0069382E */ +static void peep_update_ride_sub_state_9(rct_peep* peep){ + sint16 x, y, xy_distance; + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + + if (xy_distance >= 16){ + sint16 z = ride->station_heights[peep->current_ride_station] * 8; + + z += RCT2_ADDRESS(0x97D21C, uint8)[ride->type * 8]; + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + sub_693BE5(peep, 0); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO){ + uint8 secondaryItem = RCT2_ADDRESS(0x0097D7CB, uint8)[ride->type * 4]; + if (!(RCT2_CALLPROC_X(0x0069AF1E, secondaryItem | (peep->current_ride << 8), 0, ride->price_secondary, 0, (int)peep, 0, 0) & 0x100)){ + ride->no_secondary_items_sold++; + } + } + peep->sub_state = 18; +} + +/* rct2: 0x006926AD */ +static void peep_update_ride_sub_state_12(rct_peep* peep){ + sint16 x, y, xy_distance; + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + sint16 z; + if (ride->type == RIDE_TYPE_MOTION_SIMULATOR){ + z = ride->station_heights[peep->current_ride_station] * 8 + 2; + + if ((peep->var_37 & 3) == 2){ + xy_distance -= 12; + if (xy_distance < 0) + xy_distance = 0; + + if (xy_distance <= 15){ + z += 15 - xy_distance; + } + } + } + else{ + z = peep->z; + } + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + if ((peep->var_37 & 3) == 2){ + peep->sub_state = 5; + return; + } + + peep->var_37++; + + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + x *= 32; + y *= 32; + x += 16; + y += 16; + + if (ride->type == RIDE_TYPE_ENTERPRISE){ + x = vehicle->x; + y = vehicle->y; + } + + rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype); + rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type]; + + x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1]; + y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2]; + + peep->destination_x = x; + peep->destination_y = y; +} + +/* rct2: 0x0069357D */ +static void peep_udpate_ride_sub_state_13(rct_peep* peep){ + sint16 x, y, xy_distance; + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + sint16 z; + if (ride->type == RIDE_TYPE_MOTION_SIMULATOR){ + z = ride->station_heights[peep->current_ride_station] * 8 + 2; + + if ((peep->var_37 & 3) == 1){ + + if (xy_distance > 15) + xy_distance = 15; + + z += xy_distance; + } + } + else{ + z = peep->z; + } + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + if ((peep->var_37 & 3) != 0){ + if ((peep->var_37 & 3) == 3){ + peep_update_ride_prepare_for_state_9(peep); + return; + } + + peep->var_37--; + rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]); + + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + x *= 32; + y *= 32; + x += 16; + y += 16; + + if (ride->type == RIDE_TYPE_ENTERPRISE){ + x = vehicle->x; + y = vehicle->y; + } + + rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype); + rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type]; + + x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1]; + y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2]; + + peep->destination_x = x; + peep->destination_y = y; + } + + peep->var_37 |= 3; + + x = ride->exits[peep->current_ride_station] & 0xFF; + y = ride->exits[peep->current_ride_station] >> 8; + sint16 z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + exit_direction ^= (1 << 1); + + x *= 32; + y *= 32; + x += 16; + y += 16; + + sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2]; + sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2]; + + sint16 shift_multiplier = 20; + + rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype); + rct_ride_type_vehicle* vehicle_entry = &ride_type->vehicles[ride_type->default_vehicle]; + if (vehicle_entry->var_14 & 0x5000){ + shift_multiplier = 32; + } + + x_shift *= shift_multiplier; + y_shift *= shift_multiplier; + + x -= x_shift; + y -= y_shift; + + peep->destination_x = x; + peep->destination_y = y; +} + +/* rct2: 0x006927B3 */ +static void peep_update_ride_sub_state_14(rct_peep* peep){ + sint16 x, y, xy_distance; + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + if ((peep->var_37 & 3) == 3){ + peep->sub_state = 15; + peep->destination_x = 0; + peep->destination_y = 0; + peep->var_37 = (peep->var_37 / 4) & 0xC; + sprite_move(0x8000, y, peep->z, (rct_sprite*)peep); + return; + } + else if ((peep->var_37 & 3) == 2){ + uint8 last_ride = 0; + if (ride->status != RIDE_STATUS_OPEN) + last_ride = 1; + else if (peep->current_car++ != 0){ + if (ride->mode == RIDE_MODE_SINGLE_RIDE_PER_ADMISSION) + last_ride = 1; + if ((uint8)(peep->current_car - 1) > (scenario_rand() & 0xF)) + last_ride = 1; + } + + if (last_ride){ + x = ride->exits[peep->current_ride_station] & 0xFF; + y = ride->exits[peep->current_ride_station] >> 8; + sint16 z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + peep->var_37 = (exit_direction * 4) | (peep->var_37 & 0x30) | 1; + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + x *= 32; + y *= 32; + sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type]; + + x += edx[0]; + y += edx[1]; + + peep->destination_x = x; + peep->destination_y = y; + peep->sub_state = 16; + return; + } + } + peep->var_37++; + + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + x *= 32; + y *= 32; + sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type]; + + x += edx[0]; + y += edx[1]; + + peep->destination_x = x; + peep->destination_y = y; +} + +/* rct2: 0x00692D83 */ +static void peep_update_ride_sub_state_15(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (ride->type != RIDE_TYPE_SPIRAL_SLIDE) + return; + + if ((peep->var_37 & 3) == 0){ + switch (peep->destination_x){ + case 0: + peep->destination_y++; + if (peep->destination_y >= 30) + peep->destination_x++; + return; + case 1: + if (ride->var_15D != 0) + return; + + ride->var_15D++; + ride->slide_peep = peep->sprite_index; + ride->slide_peep_t_shirt_colour = peep->tshirt_colour; + ride->var_176 = 0; + peep->destination_x++; + return; + case 2: + return; + case 3: + { + sint16 x = ride->station_starts[peep->current_ride_station] & 0xFF; + sint16 y = ride->station_starts[peep->current_ride_station] >> 8; + + x *= 32; + y *= 32; + + uint8 direction = (peep->var_37 / 4) & 3; + sint16 dest_x = x + RCT2_ADDRESS(0x981F1C, sint16)[direction * 2]; + sint16 dest_y = y + RCT2_ADDRESS(0x981F1E, sint16)[direction * 2]; + + peep->destination_x = dest_x; + peep->destination_y = dest_y; + + x += RCT2_ADDRESS(0x981F0C, sint16)[direction * 2]; + y += RCT2_ADDRESS(0x981F0E, sint16)[direction * 2]; + + sprite_move(x, y, peep->z, (rct_sprite*)peep); + + peep->sprite_direction = (peep->var_37 & 0xC) * 2; + + invalidate_sprite((rct_sprite*)peep); + + peep->var_37++; + return; + } + default: + return; + } + } + + sint16 x, y, xy_distance; + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + peep->var_37 = (peep->var_37 * 4 & 0x30) + 2; + + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + x *= 32; + y *= 32; + sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type]; + + x += edx[0]; + y += edx[1]; + + peep->destination_x = x; + peep->destination_y = y; + peep->sub_state = 14; +} + +/* rct2: 0x00692C6B */ +static void peep_update_ride_sub_state_16(rct_peep* peep){ + sint16 x, y, xy_distance; + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + rct_ride* ride = GET_RIDE(peep->current_ride); + + if ((peep->var_37 & 0x3) != 0){ + if ((peep->var_37 & 0x3) == 3){ + peep_update_ride_prepare_for_state_9(peep); + return; + } + + peep->var_37--; + x = ride->station_starts[peep->current_ride_station] & 0xFF; + y = ride->station_starts[peep->current_ride_station] >> 8; + + x *= 32; + y *= 32; + sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type]; + + x += edx[0]; + y += edx[1]; + + peep->destination_x = x; + peep->destination_y = y; + return; + } + + peep->var_37 |= 3; + + x = ride->exits[peep->current_ride_station] & 0xFF; + y = ride->exits[peep->current_ride_station] >> 8; + sint16 z = ride->station_heights[peep->current_ride_station]; + + rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z); + + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + exit_direction ^= (1 << 1); + + x *= 32; + y *= 32; + x += 16; + y += 16; + + sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2]; + sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2]; + + sint16 shift_multiplier = 20; + + x_shift *= shift_multiplier; + y_shift *= shift_multiplier; + + x -= x_shift; + y -= y_shift; + + peep->destination_x = x; + peep->destination_y = y; +} + +/* rct2: 0x00692A83 */ +static void peep_update_ride_sub_state_17(rct_peep* peep){ + sint16 x, y, xy_distance; + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + rct_ride* ride = GET_RIDE(peep->current_ride); + if (peep->var_37 == 16){ + peep_update_ride_prepare_for_state_9(peep); + return; + } + + if (peep->action >= PEEP_ACTION_NONE_1){ + if (peep->energy > 64 && + (scenario_rand() & 0xFFFF) <= 2427){ + + peep->action = PEEP_ACTION_JUMP; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + sub_693B58(peep); + invalidate_sprite((rct_sprite*)peep); + } + } + + x = peep->destination_x & 0xFFE0; + y = peep->destination_y & 0xFFE0; + sint16 z = ride->station_heights[0]; + + // Find the station track element + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK && z == mapElement->base_height) + break; + + } while (!map_element_is_last_for_tile(mapElement++)); + + uint16 maze_entry = mapElement->properties.track.maze_entry; + uint16 open_hedges = 0; + uint8 var_37 = peep->var_37; + + if (maze_entry & (1 << RCT2_ADDRESS(0x981FF4, uint8)[var_37])){ + open_hedges = 1; + } + open_hedges <<= 1; + if (maze_entry & (1 << RCT2_ADDRESS(0x981FF3, uint8)[var_37])){ + open_hedges |= 1; + } + open_hedges <<= 1; + if (maze_entry & (1 << RCT2_ADDRESS(0x981FF2, uint8)[var_37])){ + open_hedges |= 1; + } + open_hedges <<= 1; + if (maze_entry & (1 << RCT2_ADDRESS(0x981FF1, uint8)[var_37])){ + open_hedges |= 1; + } + + open_hedges ^= 0xF; + if (open_hedges == 0) + return; + + uint8 maze_last_edge = peep->maze_last_edge ^ (1 << 1); + open_hedges &= ~(1 << maze_last_edge); + if (open_hedges == 0) + open_hedges |= (1 << maze_last_edge); + + uint8 chosen_edge = scenario_rand() & 0x3; + while (!(open_hedges & (1 << chosen_edge))){ + chosen_edge = (chosen_edge + 1) & 3; + } + + x = RCT2_ADDRESS(0x993CCC, sint16)[chosen_edge * 2] / 2; + y = RCT2_ADDRESS(0x993CCE, sint16)[chosen_edge * 2] / 2; + + x += peep->destination_x; + y += peep->destination_y; + + uint8 type = 0; + + mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (z != mapElement->base_height) + continue; + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK){ + type = 1; + break; + } + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE && + mapElement->properties.entrance.type == ENTRANCE_TYPE_RIDE_EXIT){ + type = 2; + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + switch (type){ + case 0: + peep->maze_last_edge++; + peep->maze_last_edge &= 3; + return; + case 1: + peep->destination_x = x; + peep->destination_y = y; + + peep->var_37 = RCT2_ADDRESS(0x981FE1, uint8)[peep->var_37 + chosen_edge]; + peep->maze_last_edge = chosen_edge; + break; + case 2: + x = peep->destination_x; + y = peep->destination_y; + if (chosen_edge & 1){ + x &= 0xFFE0; + x += 16; + } + else{ + y &= 0xFFE0; + y += 16; + } + peep->destination_x = x; + peep->destination_y = y; + peep->var_37 = 16; + peep->maze_last_edge = chosen_edge; + break; + } + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } +} + +/* rct2: 0x006938D2 */ +static void peep_update_ride_sub_state_18(rct_peep* peep){ + sint16 x, y, xy_distance; + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, ride->station_heights[peep->current_ride_station] * 8, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride | (1 << 8), (int)peep, 0, 0); + + if (peep->flags & PEEP_FLAGS_TRACKING){ + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954, uint32) = peep->id; + RCT2_GLOBAL(0x13CE958, uint16) = ride->name; + RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments; + + news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, 1934, peep->sprite_index); + } + + peep->var_79 = 0xFF; + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + + x = peep->x & 0xFFE0; + y = peep->y & 0xFFE0; + + // Find the station track element + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + sint16 z = map_height_from_slope(peep->x, peep->y, mapElement->properties.path.type); + z += mapElement->base_height * 8; + + sint16 z_diff = peep->z - z; + if (z_diff > 0 || z_diff < -16) + continue; + + sprite_move(peep->x, peep->y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/* rct2: 0x0069299C */ +static void peep_update_ride_sub_state_19(rct_peep* peep){ + sint16 x, y, xy_distance; + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + return; + } + + peep->sub_state++; +} + +/* rct2: 0x006929BB */ +static void peep_update_ride_sub_state_20(rct_peep* peep){ + sint16 x, y; + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (ride->type == RIDE_TYPE_FIRST_AID){ + if (peep->nausea <= 35){ + peep->sub_state++; + + x = peep->next_x + 16; + y = peep->next_y + 16; + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 3; + peep->happiness_growth_rate = min(peep->happiness_growth_rate + 30, 0xFF); + peep->happiness = peep->happiness_growth_rate; + } + else{ + peep->nausea--; + peep->nausea_growth_rate = peep->nausea; + } + return; + } + + if (peep->bathroom != 0){ + peep->bathroom--; + return; + } + + sound_play_panned(SOUND_TOILET_FLUSH, 0x8001, peep->x, peep->y, peep->z); + + peep->sub_state++; + + x = peep->next_x + 16; + y = peep->next_y + 16; + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 3; + + peep->happiness_growth_rate = min(peep->happiness_growth_rate + 30, 0xFF); + peep->happiness = peep->happiness_growth_rate; + + peep_stop_purchase_thought(peep, ride->type); +} + +/* rct2: 0x00692935 */ +static void peep_update_ride_sub_state_21(rct_peep* peep){ + sint16 x, y, xy_distance; + + if (peep_update_action(&x, &y, &xy_distance, peep)){ + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + + x = peep->x & 0xFFE0; + y = peep->y & 0xFFE0; + if (x != peep->next_x) + return; + if (y != peep->next_y) + return; + } + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_WALKING; + peep_window_state_update(peep); + + rct_ride* ride = GET_RIDE(peep->current_ride); + ride->total_customers++; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; + + ride_update_satisfaction(ride, peep->happiness / 64); +} + /* rct2: 0x691A30 - * Also used by entering_ride and queueing_front */ -static void peep_update_leaving_ride(rct_peep* peep){ - RCT2_CALLPROC_X(RCT2_ADDRESS(0x9820DC, int)[peep->var_2C], 0, 0, 0, 0, (int)peep, 0, 0); + * Used by entering_ride and queueing_front */ +static void peep_update_ride(rct_peep* peep){ + switch (peep->sub_state){ + case 0: + peep_update_ride_sub_state_0(peep); + break; + case 1: + peep_update_ride_sub_state_1(peep); + break; + case 2: + peep_update_ride_sub_state_2(peep); + break; + case 3: + peep_update_ride_sub_state_1(peep); + break; + case 4: + { + sint16 x, y, xy_distance; + if (!peep_update_action(&x, &y, &xy_distance, peep)) + { + peep->sub_state = 5; + break; + } + + invalidate_sprite((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + break; + } + case 5: + peep_update_ride_sub_state_5(peep); + break; + case 6: + // No action, on ride. + break; + case 7: + peep_update_ride_sub_state_7(peep); + break; + case 8: + peep_update_ride_sub_state_8(peep); + break; + case 9: + peep_update_ride_sub_state_9(peep); + break; + case 10: + case 11: + assert(false); + break; + case 12: + peep_update_ride_sub_state_12(peep); + break; + case 13: + peep_udpate_ride_sub_state_13(peep); + break; + case 14: + peep_update_ride_sub_state_14(peep); + break; + case 15: + peep_update_ride_sub_state_15(peep); + break; + case 16: + peep_update_ride_sub_state_16(peep); + break; + case 17: + peep_update_ride_sub_state_17(peep); + break; + case 18: + peep_update_ride_sub_state_18(peep); + break; + case 19: + peep_update_ride_sub_state_19(peep); + break; + case 20: + peep_update_ride_sub_state_20(peep); + break; + case 21: + peep_update_ride_sub_state_21(peep); + break; + default: + RCT2_CALLPROC_X(RCT2_ADDRESS(0x9820DC, int)[peep->sub_state], 0, 0, 0, 0, (int)peep, 0, 0); + } +} + +/* rct2: 0x006C0E8B + * Also used by inspecting. + */ +static void peep_update_fixing(int steps, rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (ride->type == RIDE_TYPE_NULL) + { + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + RCT2_CALLPROC_X(RCT2_ADDRESS(0x006C0EB0, uint32)[peep->sub_state], steps, 0, 0, 0, (int)peep, (int)ride, 0); } /** @@ -568,56 +2622,57 @@ static void peep_update_leaving_ride(rct_peep* peep){ */ static void peep_update_queuing(rct_peep* peep){ if (!sub_68F3AE(peep)){ - RCT2_CALLPROC_X(0x6966A9, 0, 0, 0, 0, (int)peep, 0, 0); + remove_peep_from_queue(peep); return; } rct_ride* ride = GET_RIDE(peep->current_ride); if (ride->status == RIDE_STATUS_CLOSED || ride->status == RIDE_STATUS_TESTING){ - RCT2_CALLPROC_X(0x6966A9, 0, 0, 0, 0, (int)peep, 0, 0); + remove_peep_from_queue(peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_1; peep_window_state_update(peep); return; } - if (peep->var_2C != 0xA){ - if (peep->var_74 == 0xFFFF){ + if (peep->sub_state != 10){ + if (peep->next_in_queue == 0xFFFF){ //Happens every time peep goes onto ride. peep->destination_tolerence = 0; peep_decrement_num_riders(peep); peep->state = PEEP_STATE_QUEUING_FRONT; peep_window_state_update(peep); - peep->var_2C = 0; + peep->sub_state = 0; return; } //Give up queueing for the ride peep->sprite_direction ^= (1 << 4); invalidate_sprite((rct_sprite*)peep); - RCT2_CALLPROC_X(0x6966A9, 0, 0, 0, 0, (int)peep, 0, 0); + remove_peep_from_queue(peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_1; peep_window_state_update(peep); + return; } RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); if (peep->action < 0xFE)return; if (peep->sprite_type == 0){ - if (peep->var_7A >= 2000 && (0xFFFF & scenario_rand()) <= 119){ - // Look at watch - peep->action = PEEP_ACTION_CHECK_WATCH; + if (peep->time_in_queue >= 2000 && (0xFFFF & scenario_rand()) <= 119){ + // Eat Food/Look at watch + peep->action = PEEP_ACTION_EAT_FOOD; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); } - if (peep->var_7A >= 3500 && (0xFFFF & scenario_rand()) <= 93) + if (peep->time_in_queue >= 3500 && (0xFFFF & scenario_rand()) <= 93) { //Create the ive been waiting in line ages thought peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_QUEUING_AGES, peep->current_ride); } } else{ - if (!(peep->var_7A & 0x3F) && peep->action == 0xFE && peep->var_6F == 2){ + if (!(peep->time_in_queue & 0x3F) && peep->action == 0xFE && peep->var_6F == 2){ switch (peep->sprite_type){ case 0xF: case 0x10: @@ -641,23 +2696,23 @@ static void peep_update_queuing(rct_peep* peep){ case 0x2D: case 0x2E: case 0x2F: - // Look at watch - peep->action = PEEP_ACTION_CHECK_WATCH; + // Eat food/Look at watch + peep->action = PEEP_ACTION_EAT_FOOD; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); break; } } } - if (peep->var_7A < 4300) return; + if (peep->time_in_queue < 4300) return; if (peep->happiness <= 65 && (0xFFFF & scenario_rand()) < 2184){ //Give up queueing for the ride peep->sprite_direction ^= (1 << 4); invalidate_sprite((rct_sprite*)peep); - RCT2_CALLPROC_X(0x6966A9, 0, 0, 0, 0, (int)peep, 0, 0); + remove_peep_from_queue(peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_1; peep_window_state_update(peep); @@ -671,8 +2726,8 @@ static void peep_update_mowing(rct_peep* peep){ invalidate_sprite((rct_sprite*)peep); while (1){ - sint16 x = 0, y = 0; - if (sub_6939EB(&x, &y, peep)){ + sint16 x = 0, y = 0, xy_distance; + if (peep_update_action(&x, &y, &xy_distance, peep)){ int eax = x, ebx, ecx = y, z, ebp, edi; RCT2_CALLFUNC_X(0x662783, &eax, &ebx, &ecx, &z, (int*)&peep, &edi, &ebp); @@ -686,7 +2741,7 @@ static void peep_update_mowing(rct_peep* peep){ peep->var_37++; if (peep->var_37 == 1){ - RCT2_CALLPROC_X(0x00693BE5, 2, 0, 0, 0, (int)peep, 0, 0); + sub_693BE5(peep, 2); } if (RCT2_ADDRESS(0x9929C8, uint16)[peep->var_37 * 2] == 0xFFFF){ @@ -699,13 +2754,13 @@ static void peep_update_mowing(rct_peep* peep){ if (peep->var_37 != 7)continue; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER((peep->next_x | (peep->next_y << 8)) >> 5); + rct_map_element *map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); - for (; ((map_element->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_SURFACE); map_element++); + for (; (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SURFACE); map_element++); if ((map_element->properties.surface.terrain & MAP_ELEMENT_SURFACE_TERRAIN_MASK) == (TERRAIN_GRASS << 5)){ map_element->properties.surface.grass_length = 0; - gfx_invalidate_scrollingtext(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->base_height * 8 + 16); + gfx_invalidate_tile_if_zoomed(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->base_height * 8 + 16); } peep->staff_lawns_mown++; peep->var_45 |= (1 << 5); @@ -715,7 +2770,7 @@ static void peep_update_mowing(rct_peep* peep){ /* rct2: 0x006BF7E6 */ static void peep_update_watering(rct_peep* peep){ peep->var_E2 = 0; - if (peep->var_2C == 0){ + if (peep->sub_state == 0){ if (!sub_68F3AE(peep))return; RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); @@ -724,42 +2779,43 @@ static void peep_update_watering(rct_peep* peep){ peep->sprite_direction = (peep->var_37 & 3) << 3; peep->action = PEEP_ACTION_STAFF_WATERING; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); - peep->var_2C = 1; + peep->sub_state = 1; } - else if (peep->var_2C == 1){ + else if (peep->sub_state == 1){ if (peep->action != PEEP_ACTION_NONE_2){ - sint16 x, y; - sub_6939EB(&x, &y, peep); + sint16 x, y, xy_distance; + peep_update_action(&x, &y, &xy_distance, peep); return; } int x = peep->next_x + RCT2_ADDRESS(0x993CCC, sint16)[peep->var_37 * 2]; int y = peep->next_y + RCT2_ADDRESS(0x993CCE, sint16)[peep->var_37 * 2]; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER((x | (y << 8)) >> 5); + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); - for (;; map_element++){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_SCENERY){ - if (abs((peep->next_z & 0xFF) - map_element->base_height) <= 4){ - rct_scenery_entry* scenery_entry = g_smallSceneryEntries[map_element->properties.scenery.type]; + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY) + continue; + + if (abs(((int)peep->next_z) - map_element->base_height) > 4) + continue; + + rct_scenery_entry* scenery_entry = g_smallSceneryEntries[map_element->properties.scenery.type]; - if (scenery_entry->small_scenery.flags& SMALL_SCENERY_FLAG6){ - map_element->properties.scenery.age = 0; - gfx_invalidate_scrollingtext(x, y, map_element->base_height * 8, map_element->clearance_height * 8); - peep->staff_gardens_watered++; - peep->var_45 |= (1 << 4); - } - } - } - if (map_element->flags&MAP_ELEMENT_FLAG_LAST_TILE){ - peep_state_reset(peep); - return; - } - } + if (!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_CAN_BE_WATERED)) + continue; + + map_element->properties.scenery.age = 0; + gfx_invalidate_tile_if_zoomed(x, y, map_element->base_height * 8, map_element->clearance_height * 8); + peep->staff_gardens_watered++; + peep->var_45 |= (1 << 4); + } while (!map_element_is_last_for_tile(map_element++)); + + peep_state_reset(peep); } } @@ -767,7 +2823,7 @@ static void peep_update_watering(rct_peep* peep){ static void peep_update_emptying_bin(rct_peep* peep){ peep->var_E2 = 0; - if (peep->var_2C == 0){ + if (peep->sub_state == 0){ if (!sub_68F3AE(peep))return; RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); @@ -776,52 +2832,55 @@ static void peep_update_emptying_bin(rct_peep* peep){ peep->sprite_direction = (peep->var_37 & 3) << 3; peep->action = PEEP_ACTION_STAFF_EMPTY_BIN; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); - peep->var_2C = 1; + peep->sub_state = 1; } - else if (peep->var_2C == 1){ + else if (peep->sub_state == 1){ if (peep->action == PEEP_ACTION_NONE_2){ peep_state_reset(peep); return; } - sint16 x = 0, y = 0; - sub_6939EB(&x, &y, peep); + sint16 x = 0, y = 0, xy_distance; + peep_update_action(&x, &y, &xy_distance, peep); if (peep->action_frame != 11)return; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER((peep->next_x | (peep->next_y << 8)) >> 5); + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); - for (;; map_element++){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH){ - if ((peep->next_z & 0xFF) == map_element->base_height)break; + for (;; map_element++) { + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH) { + if (peep->next_z == map_element->base_height) + break; } - if (map_element->flags&MAP_ELEMENT_FLAG_LAST_TILE){ + if (map_element_is_last_for_tile(map_element)) { peep_state_reset(peep); return; } } - if ((map_element->properties.path.additions & 0xF) == 0){ + if ((map_element->properties.path.additions & 0x0F) == 0) { peep_state_reset(peep); return; } rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[(map_element->properties.path.additions & 0xF) - 1]; - if (!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG1) - || map_element->flags&(1 << 5) - || map_element->properties.path.additions & (1 << 7)){ + if ( + !(scenery_entry->path_bit.var_06 & 1) + || map_element->flags & (1 << 5) + || map_element->properties.path.additions & (1 << 7) + ) { peep_state_reset(peep); return; } - map_element->properties.path.addition_status = ((3 << peep->var_37) << peep->var_37); + map_element->properties.path.addition_status |= ((3 << peep->var_37) << peep->var_37); - gfx_invalidate_scrollingtext(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->clearance_height * 8); + gfx_invalidate_tile_if_zoomed(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->clearance_height * 8); peep->staff_bins_emptied++; peep->var_45 |= (1 << 4); @@ -841,8 +2900,8 @@ static void peep_update_sweeping(rct_peep* peep){ peep->staff_litter_swept++; peep->var_45 |= (1 << 4); } - sint16 x = 0, y = 0; - if (sub_6939EB(&x, &y, peep)){ + sint16 x = 0, y = 0, xy_distance; + if (peep_update_action(&x, &y, &xy_distance, peep)){ int eax = x, ebx, ecx = y, z, ebp, edi; RCT2_CALLFUNC_X(0x694921, &eax, &ebx, &ecx, &z, (int*)&peep, &edi, &ebp); @@ -857,7 +2916,7 @@ static void peep_update_sweeping(rct_peep* peep){ if (peep->var_37 != 2){ peep->action = PEEP_ACTION_STAFF_SWEEP; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); return; @@ -890,8 +2949,8 @@ static void peep_update_1(rct_peep* peep){ */ static void peep_update_picked(rct_peep* peep){ if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x1F) return; - peep->var_2C++; - if (peep->var_2C == 13){ + peep->sub_state++; + if (peep->sub_state == 13){ peep_insert_new_thought(peep, PEEP_THOUGHT_HELP, 0xFF); } } @@ -901,12 +2960,12 @@ static void peep_update_leaving_park(rct_peep* peep){ if (peep->var_37 != 0){ RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 2))return; - RCT2_CALLPROC_X(0x69A535, 0, 0, 0, 0, (int)peep, 0, 0); + peep_sprite_remove(peep); return; } - sint16 x = 0, y = 0; - if (sub_6939EB(&x, &y, peep)){ + sint16 x = 0, y = 0, xy_distance; + if (peep_update_action(&x, &y, &xy_distance, peep)){ invalidate_sprite((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); invalidate_sprite((rct_sprite*)peep); @@ -916,19 +2975,19 @@ static void peep_update_leaving_park(rct_peep* peep){ peep->var_2A = 1; peep->destination_tolerence = 5; RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)--; - RCT2_GLOBAL(0x9A9804, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT; peep->var_37 = 1; window_invalidate_by_class(WC_GUEST_LIST); RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 2))return; - RCT2_CALLPROC_X(0x69A535, 0, 0, 0, 0, (int)peep, 0, 0); + peep_sprite_remove(peep); } /* rct2: 0x6916D6 */ static void peep_update_watching(rct_peep* peep){ - if (peep->var_2C == 0){ + if (peep->sub_state == 0){ if (!sub_68F3AE(peep))return; RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); @@ -943,18 +3002,18 @@ static void peep_update_watching(rct_peep* peep){ peep->action = 0xFE; peep->var_6F = 2; - RCT2_CALLPROC_X(0x693BAB, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693BAB(peep); - peep->var_2C++; + peep->sub_state++; peep->time_to_stand = clamp(0, ((129 - peep->energy) * 16 + 50) / 2, 255); - RCT2_CALLPROC_X(0x0069B8CC, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_sprite_type(peep); } - else if (peep->var_2C == 1){ + else if (peep->sub_state == 1){ if (peep->action < 0xFE){ //6917F6 - sint16 x = 0, y = 0; - sub_6939EB(&x, &y, peep); + sint16 x = 0, y = 0, xy_distance; + peep_update_action(&x, &y, &xy_distance, peep); if (peep->action != 0xFF)return; peep->action = 0xFE; @@ -962,9 +3021,9 @@ static void peep_update_watching(rct_peep* peep){ else{ if (peep_has_food(peep)){ if ((scenario_rand() & 0xFFFF) <= 1310){ - peep->action = PEEP_ACTION_CHECK_WATCH; + peep->action = PEEP_ACTION_EAT_FOOD; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); return; @@ -974,7 +3033,7 @@ static void peep_update_watching(rct_peep* peep){ if ((scenario_rand() & 0xFFFF) <= 655){ peep->action = PEEP_ACTION_TAKE_PHOTO; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); return; @@ -984,7 +3043,7 @@ static void peep_update_watching(rct_peep* peep){ if ((scenario_rand() & 0xFFFF) <= 655){ peep->action = PEEP_ACTION_WAVE; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); return; @@ -1001,7 +3060,7 @@ static void peep_update_watching(rct_peep* peep){ peep_decrement_num_riders(peep); peep->state = PEEP_STATE_WALKING; peep_window_state_update(peep); - RCT2_CALLPROC_X(0x0069B8CC, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_sprite_type(peep); // Send peep to the center of current tile. peep->destination_x = (peep->x & 0xFFE0) + 16; peep->destination_y = (peep->y & 0xFFE0) + 16; @@ -1018,12 +3077,12 @@ static void peep_update_entering_park(rct_peep* peep){ RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); if ((RCT2_GLOBAL(0xF1EE18, uint16) & 2)){ RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; - RCT2_CALLPROC_X(0x69A535, 0, 0, 0, 0, (int)peep, 0, 0); + peep_sprite_remove(peep); } return; } - sint16 x = 0, y = 0; - if (sub_6939EB(&x, &y, peep)){ + sint16 x = 0, y = 0, xy_distance; + if (peep_update_action(&x, &y, &xy_distance, peep)){ invalidate_sprite((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); invalidate_sprite((rct_sprite*)peep); @@ -1037,10 +3096,1101 @@ static void peep_update_entering_park(rct_peep* peep){ peep->time_in_park = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, sint32); RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)++; RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; - RCT2_GLOBAL(0x9A9804, uint16) |= (1 << 2); + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT; window_invalidate_by_class(WC_GUEST_LIST); } +/* rct2: 0x00690582*/ +static int peep_update_walking_find_bench(rct_peep* peep){ + if (!peep_should_find_bench(peep))return 0; + + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); + + for (;; map_element++){ + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){ + if (peep->next_z == map_element->base_height)break; + } + if (map_element_is_last_for_tile(map_element)){ + return 0; + } + } + + uint8 additions = map_element->properties.path.additions & 0xF; + + if (!additions) return 0; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + + if (!(sceneryEntry->path_bit.var_06 & 0x2))return 0; + + if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return 0; + + if (map_element->properties.path.additions & 0x80)return 0; + + int edges = (map_element->properties.path.edges & 0xF) ^ 0xF; + if (edges == 0) return 0; + + uint8 chosen_edge = scenario_rand() & 0x3; + + for (; !(edges & (1 << chosen_edge));)chosen_edge = (chosen_edge + 1) & 0x3; + + uint16 sprite_id = RCT2_ADDRESS(0xF1EF60, uint16)[((peep->x & 0x1FE0) << 3) | (peep->y >> 5)]; + uint8 free_edge = 3; + + for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->unknown.next_in_quadrant){ + sprite = &g_sprite_list[sprite_id]; + + if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_PEEP)continue; + + if (sprite->peep.state != PEEP_STATE_SITTING)continue; + + if (peep->z != sprite->peep.z)continue; + + if ((sprite->peep.var_37 & 0x3) != chosen_edge)continue; + + free_edge &= ~(1 << ((sprite->peep.var_37 & 0x4) >> 2)); + } + + if (!free_edge) return 0; + + free_edge ^= 0x3; + if (!free_edge){ + if (scenario_rand() & 0x8000000) free_edge = 1; + } + + peep->var_37 = ((free_edge & 1) << 2) | chosen_edge; + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_SITTING; + peep_window_state_update(peep); + + peep->sub_state = 0; + + int ebx = peep->var_37 & 0x7; + int x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x981F2C, uint16)[ebx * 2]; + int y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x981F2E, uint16)[ebx * 2]; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 3; + + return 1; +} + +static int peep_update_walking_find_bin(rct_peep* peep){ + if (!peep_has_empty_container(peep)) return 0; + + if (peep->next_var_29 & 0x18)return 0; + + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); + + for (;; map_element++){ + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){ + if (peep->next_z == map_element->base_height)break; + } + if (map_element_is_last_for_tile(map_element)){ + return 0; + } + } + + uint8 additions = map_element->properties.path.additions & 0xF; + + if (!additions) return 0; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + + if (!(sceneryEntry->path_bit.var_06 & 0x1))return 0; + + if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return 0; + + if (map_element->properties.path.additions & 0x80)return 0; + + int edges = (map_element->properties.path.edges & 0xF) ^ 0xF; + if (edges == 0) return 0; + + uint8 chosen_edge = scenario_rand() & 0x3; + + // Note: Bin qunatity is inverted 0 = full, 3 = empty + uint8 bin_quantities = map_element->properties.path.addition_status; + + // Rotate the bin to the correct edge. Makes it easier for next calc. + bin_quantities = ror8(ror8(bin_quantities, chosen_edge), chosen_edge); + + for (uint8 free_edge = 4; free_edge != 0; free_edge--){ + // If not full + if (bin_quantities & 0x3){ + if (edges&(1 << chosen_edge))break; + } + chosen_edge = (chosen_edge + 1) & 0x3; + bin_quantities = ror8(bin_quantities, 2); + if ((free_edge - 1) == 0) return 0; + } + + peep->var_37 = chosen_edge; + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_USING_BIN; + peep_window_state_update(peep); + + peep->sub_state = 0; + + int ebx = peep->var_37 & 0x3; + int x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x992A4C, uint16)[ebx * 2]; + int y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x992A4E, uint16)[ebx * 2]; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 3; + + return 1; +} + +/* rct2: 0x00690848*/ +static void peep_update_walking_break_scenery(rct_peep* peep){ + if (!(peep->flags & PEEP_FLAGS_ANGRY)){ + if (peep->happiness >= 48) return; + if (peep->energy < 85) return; + if (peep->state != PEEP_STATE_WALKING) return; + + if ((peep->var_E1 & 0xC0) != 0xC0 && + (peep->var_E3 & 0xC0) != 0xC0) return; + + if ((scenario_rand() & 0xFFFF) > 3276) return; + } + + if (peep->next_var_29 & 0x18) return; + + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); + + for (;; map_element++){ + if ( map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){ + if (peep->next_z == map_element->base_height)break; + } + if (map_element_is_last_for_tile(map_element)){ + return; + } + } + + uint8 additions = map_element->properties.path.additions & 0xF; + + if (!additions) return; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + + if (!(sceneryEntry->path_bit.var_06 & 0x4))return; + + if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return; + + if (map_element->properties.path.additions & 0x80)return; + + int edges = map_element->properties.path.edges & 0xF; + if (edges == 0xF) return; + + rct_peep* inner_peep; + uint16 sprite_index; + + FOR_ALL_STAFF(sprite_index, inner_peep){ + if (inner_peep->staff_type != STAFF_TYPE_SECURITY)continue; + + if (inner_peep->x == (sint16)SPRITE_LOCATION_NULL)continue; + + int x_diff = abs(inner_peep->x - peep->x); + int y_diff = abs(inner_peep->y - peep->y); + + if (max(x_diff, y_diff) < 224)return; + } + + map_element->flags |= MAP_ELEMENT_FLAG_BROKEN; + + map_invalidate_tile( + peep->next_x, + peep->next_y, + (map_element->base_height << 3) + 32, + map_element->base_height << 3); + + peep->var_F3 = 0x10; + + return; +} + +/* rct2: 0x006912A3 */ +static void peep_update_buying(rct_peep* peep) +{ + if (!sub_68F3AE(peep))return; + + rct_ride* ride = GET_RIDE(peep->current_ride); + if (ride->type == RIDE_TYPE_NULL || ride->status != RIDE_STATUS_OPEN){ + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + if (peep->sub_state == 1){ + if (peep->action != 0xFF){ + sint16 x, y, xy_distance; + peep_update_action(&x, &y, &xy_distance, peep); + return; + } + + if (ride->type == RIDE_TYPE_CASH_MACHINE){ + if (peep->current_ride != peep->previous_ride){ + peep->cash_in_pocket += MONEY(50,00); + } + window_invalidate_by_number(WC_PEEP, peep->sprite_index); + } + peep->sprite_direction ^= 0x10; + peep->destination_x = peep->next_x + 16; + peep->destination_y = peep->next_y + 16; + peep->var_78 ^= 2; + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_WALKING; + peep_window_state_update(peep); + return; + } + + uint8 item_bought = 0; + + if (peep->current_ride != peep->previous_ride){ + if (ride->type == RIDE_TYPE_CASH_MACHINE){ + item_bought = !(RCT2_CALLPROC_X(0x0069AEB7, peep->current_ride << 8, 0, 0, 0, (int)peep, 0, 0) & 0x100); + + if (!item_bought){ + peep->previous_ride = peep->current_ride; + peep->previous_ride_time_out = 0; + } + else{ + peep->action = PEEP_ACTION_WITHDRAW_MONEY; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + + sub_693B58(peep); + invalidate_sprite((rct_sprite*)peep); + + ride->no_primary_items_sold++; + } + } + else{ + rct_ride_type* ride_type = gRideTypeList[ride->subtype]; + if (ride_type->shop_item_secondary != 0xFF){ + money16 price = ride->price_secondary; + + item_bought = !(RCT2_CALLPROC_X(0x0069AF1E, ride_type->shop_item_secondary | (peep->current_ride << 8), 0, price, 0, (int)peep, 0, 0) & 0x100); + + if (item_bought){ + ride->no_secondary_items_sold++; + } + } + + if (!item_bought && ride_type->shop_item != 0xFF){ + money16 price = ride->price; + + item_bought = !(RCT2_CALLPROC_X(0x0069AF1E, ride_type->shop_item | (peep->current_ride << 8), 0, price, 0, (int)peep, 0, 0) & 0x100); + + if (item_bought){ + ride->no_primary_items_sold++; + } + } + } + } + + if (item_bought){ + ride_update_popularity(ride, 1); + + peep_stop_purchase_thought(peep, ride->type); + } + else{ + ride_update_popularity(ride, 0); + } + peep->sub_state = 1; + return; +} + +/* rct2: 0x00691089 */ +static void peep_update_using_bin(rct_peep* peep){ + if (peep->sub_state == 0){ + if (!sub_68F3AE(peep))return; + + RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; + + peep->sub_state = 1; + } + else if (peep->sub_state == 1){ + + if (peep->action != PEEP_ACTION_NONE_2){ + sint16 x, y, xy_distance; + peep_update_action(&x, &y, &xy_distance, peep); + return; + } + + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); + + for (;;map_element++){ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_PATH){ + continue; + } + + if (map_element->base_height == peep->next_z)break; + + if (map_element_is_last_for_tile(map_element)){ + peep_state_reset(peep); + return; + } + } + + uint8 additions = map_element->properties.path.additions & 0x0F; + if (!additions){ + peep_state_reset(peep); + return; + } + + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (!(sceneryEntry->path_bit.var_06 & 1)){ + peep_state_reset(peep); + return; + } + + if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN){ + peep_state_reset(peep); + return; + } + + if (map_element->properties.path.additions & 0x80){ + peep_state_reset(peep); + return; + } + + // Bin selection is one of 4 corners + uint8 selected_bin = peep->var_37 * 2; + + // This counts down 2 = No rubbish, 0 = full + uint8 rubbish_in_bin = 0x3 & (map_element->properties.path.addition_status >> selected_bin); + uint32 empty_containers = peep_empty_container_standard_flag(peep); + + for (uint8 cur_container = 0; cur_container < 32; cur_container++){ + if (!(empty_containers & (1 << cur_container))) continue; + + if (rubbish_in_bin != 0){ + // OpenRCT2 modification: This previously used + // the tick count as a simple random function + // switched to scenario_rand as it is more reliable + if (scenario_rand() & 7) rubbish_in_bin--; + peep->item_standard_flags &= ~(1 << cur_container); + peep->var_45 |= 8; + peep_update_sprite_type(peep); + continue; + } + uint8 bp = RCT2_ADDRESS(0x97EFCC, uint8)[cur_container]; + + int x, y; + x = peep->x + (scenario_rand() & 7) - 3; + y = peep->y + (scenario_rand() & 7) - 3; + + RCT2_CALLPROC_X(0x67375D, x, scenario_rand() & 3, y, peep->z, 0, 0, bp); + peep->item_standard_flags &= ~(1 << cur_container); + peep->var_45 |= 8; + + peep_update_sprite_type(peep); + } + + // Original bug: This would clear any rubbish placed by the previous function + //rubbish_in_bin = 0x3 & (map_element->properties.path.addition_status >> selected_bin); + empty_containers = peep_empty_container_extra_flag(peep); + + for (uint8 cur_container = 0; cur_container < 32; cur_container++){ + if (!(empty_containers & (1 << cur_container))) continue; + + if (rubbish_in_bin != 0){ + // OpenRCT2 modification: This previously used + // the tick count as a simple random function + // switched to scenario_rand as it is more reliable + if (scenario_rand() & 7) rubbish_in_bin--; + peep->item_extra_flags &= ~(1 << cur_container); + peep->var_45 |= 8; + + peep_update_sprite_type(peep); + continue; + } + uint8 bp = RCT2_ADDRESS(0x97EFE8, uint8)[cur_container]; + + int x, y; + x = peep->x + (scenario_rand() & 7) - 3; + y = peep->y + (scenario_rand() & 7) - 3; + + RCT2_CALLPROC_X(0x67375D, x, scenario_rand() & 3, y, peep->z, 0, 0, bp); + peep->item_extra_flags &= ~(1 << cur_container); + peep->var_45 |= 8; + + peep_update_sprite_type(peep); + } + + // Place new amount in bin by first clearing the value + map_element->properties.path.addition_status &= ~(3 << selected_bin); + // Then placeing the new value. + map_element->properties.path.addition_status |= rubbish_in_bin << selected_bin; + + gfx_invalidate_tile_if_zoomed(peep->next_x, peep->next_y, map_element->base_height << 3, map_element->clearance_height << 3); + peep_state_reset(peep); + } +} + +/* rct2: 0x006C16D7 */ +static void peep_update_heading_to_inspect(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (ride->type == RIDE_TYPE_NULL){ + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + if (ride->exits[peep->current_ride_station] == 0xFFFF){ + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION; + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + if (ride->mechanic_status != RIDE_MECHANIC_STATUS_HEADING || + !(ride->lifecycle_flags & RIDE_LIFECYCLE_DUE_INSPECTION)){ + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + if (peep->sub_state == 0){ + peep->var_74 = 0; + RCT2_CALLPROC_X(0x0069A98C, 0, 0, 0, 0, (int)peep, 0, 0); + peep->sub_state = 2; + } + + if (peep->sub_state <= 3){ + peep->var_74++; + if (peep->var_74 > 2500){ + if (ride->lifecycle_flags & RIDE_LIFECYCLE_DUE_INSPECTION&& + ride->mechanic_status == RIDE_MECHANIC_STATUS_HEADING){ + ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING; + } + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + if (!sub_68F3AE(peep))return; + + RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + + if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 0xC))return; + + rct_map_element* map_element = RCT2_GLOBAL(0x00F1EE1A, rct_map_element*); + + if (peep->current_ride != + map_element->properties.entrance.ride_index) + return; + + uint8 exit_index = ((map_element->properties.entrance.index & 0x70) >> 4); + + if (peep->current_ride_station != exit_index) + return; + + if (RCT2_GLOBAL(0xF1EE18, uint16)&(1 << 3)){ + if (ride->exits[exit_index] != 0xFFFF)return; + } + + uint8 direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + peep->var_78 = direction; + + int x = peep->next_x + 16 + RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2] * 53; + int y = peep->next_y + 16 + RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2] * 53; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 2; + peep->sprite_direction = direction << 3; + + peep->z = map_element->base_height * 4; + peep->sub_state = 4; + // Falls through into sub_state 4 + } + + invalidate_sprite((rct_sprite*)peep); + + sint16 delta_y = abs(peep->y - peep->destination_y); + + sint16 x, y, xy_distance; + if (!peep_update_action(&x, &y, &xy_distance, peep)){ + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_INSPECTING; + peep->sub_state = 0; + peep_window_state_update(peep); + return; + } + + int z = ride->station_heights[peep->current_ride_station] * 8; + + if (delta_y < 20){ + z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8]; + } + + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); +} + +/* rct2: 0x006C0CB8 */ +static void peep_update_answering(rct_peep* peep){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + if (ride->type == RIDE_TYPE_NULL || + ride->mechanic_status != RIDE_MECHANIC_STATUS_HEADING){ + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + if (peep->sub_state == 0){ + peep->action = PEEP_ACTION_STAFF_ANSWER_CALL; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + + sub_693B58(peep); + invalidate_sprite((rct_sprite*)peep); + + peep->sub_state = 1; + peep_window_state_update(peep); + return; + } + else if (peep->sub_state == 1){ + if (peep->action == PEEP_ACTION_NONE_2){ + peep->sub_state = 2; + peep_window_state_update(peep); + peep->var_74 = 0; + RCT2_CALLPROC_X(0x0069A98C, 0, 0, 0, 0, (int)peep, 0, 0); + return; + } + sint16 x, y, xy_distance; + peep_update_action(&x, &y, &xy_distance, peep); + return; + } + else if (peep->sub_state <= 3){ + peep->var_74++; + if (peep->var_74 > 2500){ + if (ride->mechanic_status == RIDE_MECHANIC_STATUS_HEADING){ + ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE; + } + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + + if (!sub_68F3AE(peep))return; + + RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + + if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 0xC))return; + + rct_map_element* map_element = RCT2_GLOBAL(0x00F1EE1A, rct_map_element*); + + if (peep->current_ride != + map_element->properties.entrance.ride_index) + return; + + uint8 exit_index = ((map_element->properties.entrance.index & 0x70) >> 4); + + if (peep->current_ride_station != exit_index) + return; + + if (RCT2_GLOBAL(0xF1EE18, uint16)&(1 << 3)){ + if (ride->exits[exit_index] != 0xFFFF)return; + } + + uint8 direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + peep->var_78 = direction; + + int x = peep->next_x + 16 + RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2] * 53; + int y = peep->next_y + 16 + RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2] * 53; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 2; + peep->sprite_direction = direction << 3; + + peep->z = map_element->base_height * 4; + peep->sub_state = 4; + // Falls through into sub_state 4 + } + + invalidate_sprite((rct_sprite*)peep); + + sint16 delta_y = abs(peep->y - peep->destination_y); + + sint16 x, y, xy_distance; + if (!peep_update_action(&x, &y, &xy_distance, peep)){ + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FIXING; + peep->sub_state = 0; + peep_window_state_update(peep); + return; + } + + int z = ride->station_heights[peep->current_ride_station] * 8; + + if (delta_y < 20){ + z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8]; + } + + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); +} + +/* rct2: 0x006BF483 */ +static int peep_update_patrolling_find_watering(rct_peep* peep){ + if (!(peep->staff_orders & STAFF_ORDERS_WATER_FLOWERS)) + return 0; + + uint8 chosen_position = scenario_rand() & 7; + for (int i = 0; i < 8; ++i, ++chosen_position){ + chosen_position &= 7; + + int x = peep->next_x + RCT2_ADDRESS(0x00993CCC, sint16)[chosen_position * 2]; + int y = peep->next_y + RCT2_ADDRESS(0x00993CCE, sint16)[chosen_position * 2]; + + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + + do { + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY){ + continue; + } + + uint8 z_diff = abs(peep->next_z - map_element->base_height); + + if (z_diff >= 4){ + continue; + } + + rct_scenery_entry* sceneryEntry = g_smallSceneryEntries[map_element->properties.scenery.type]; + + if (!(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_CAN_BE_WATERED)){ + continue; + } + + if (map_element->properties.scenery.age < 55){ + if (chosen_position >= 4){ + continue; + } + + if (map_element->properties.scenery.age < 40){ + continue; + } + } + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_WATERING; + peep->var_37 = chosen_position; + peep_window_state_update(peep); + + peep->sub_state = 0; + peep->destination_x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x992A5C, uint16)[chosen_position * 2]; + peep->destination_y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x992A5E, uint16)[chosen_position * 2]; + peep->destination_tolerence = 3; + + return 1; + } while (!map_element_is_last_for_tile(map_element++)); + } + return 0; +} + +/* rct2: 0x006BF3A1 */ +static int peep_update_patrolling_find_bin(rct_peep* peep){ + if (!(peep->staff_orders & STAFF_ORDERS_EMPTY_BINS)) + return 0; + + if ((peep->next_var_29 & 0x18) != 0) return 0; + + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); + if (map_element == NULL)return 0; + + for (;; map_element++){ + + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH + && (map_element->base_height == peep->next_z)) + break; + + if (map_element_is_last_for_tile(map_element)) + return 0; + } + + uint8 additions = map_element->properties.path.additions & 0xF; + + if (additions == 0)return 0; + + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + + if (!(sceneryEntry->path_bit.var_06 & 1)) + return 0; + + if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN) + return 0; + + if (map_element->properties.path.additions & 0x80) + return 0; + + uint8 bin_positions = map_element->properties.path.edges & 0xF; + uint8 bin_quantity = map_element->properties.path.addition_status; + uint8 chosen_position = 0; + + for (; chosen_position < 4; ++chosen_position){ + if (!(bin_positions & 1) && + !(bin_quantity & 3)) + break; + bin_positions >>= 1; + bin_quantity >>= 2; + } + + if (chosen_position == 4)return 0; + + peep->var_37 = chosen_position; + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_EMPTYING_BIN; + peep_window_state_update(peep); + + peep->sub_state = 0; + peep->destination_x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x992A4C, uint16)[chosen_position * 2]; + peep->destination_y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x992A4E, uint16)[chosen_position * 2]; + peep->destination_tolerence = 3; + return 1; +} + +/* rct2: 0x006BF322 */ +static int peep_update_patrolling_find_grass(rct_peep* peep){ + if (!(peep->staff_orders & STAFF_ORDERS_MOWING)) + return 0; + + if (peep->var_E2 < 12)return 0; + + if ((peep->next_var_29 & 0x18) != 8) return 0; + + rct_map_element* map_element = map_get_surface_element_at(peep->next_x / 32, peep->next_y / 32); + + if ((map_element->properties.surface.terrain & MAP_ELEMENT_SURFACE_TERRAIN_MASK) != TERRAIN_GRASS) + return 0; + + if (map_element->properties.surface.grass_length < GRASS_LENGTH_CLEAR_1) + return 0; + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_MOWING; + peep_window_state_update(peep); + peep->var_37 = 0; + peep->destination_x = peep->next_x + RCT2_ADDRESS(0x9929CA, uint16)[0 * 2]; + peep->destination_y = peep->next_y + RCT2_ADDRESS(0x9929CA, uint16)[0 * 2]; + peep->destination_tolerence = 3; + return 1; +} + +/* rct2: 0x006BF295 */ +static int peep_update_patrolling_find_sweeping(rct_peep* peep){ + if (!(peep->staff_orders & STAFF_ORDERS_SWEEPING)) + return 0; + + uint16 sprite_id = RCT2_ADDRESS(0xF1EF60, uint16)[((peep->x & 0x1FE0) << 3) | (peep->y >> 5)]; + + for (rct_sprite* sprite = NULL; + sprite_id != 0xFFFF; + sprite_id = sprite->unknown.next_in_quadrant){ + + sprite = &g_sprite_list[sprite_id]; + + if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_LITTER)continue; + + uint16 z_diff = abs(peep->z - sprite->litter.z); + + if (z_diff >= 16)continue; + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_SWEEPING; + peep_window_state_update(peep); + peep->var_37 = 0; + peep->destination_x = sprite->litter.x; + peep->destination_y = sprite->litter.y; + peep->destination_tolerence = 5; + return 1; + } + + return 0; +} + +/* rct2: 0x006BF1FD */ +static void peep_update_patrolling(rct_peep* peep){ + + if (!sub_68F3AE(peep))return; + + RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; + + if ((peep->next_var_29 & 0x18) == 8){ + rct_map_element* map_element = map_get_surface_element_at(peep->next_x / 32, peep->next_y / 32); + + if (map_element != NULL){ + int water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + if (water_height){ + invalidate_sprite((rct_sprite*)peep); + water_height *= 16; + sprite_move(peep->x, peep->y, water_height, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + } + } + + if (peep->staff_type != STAFF_TYPE_HANDYMAN) return; + + if (peep_update_patrolling_find_sweeping(peep))return; + + if (peep_update_patrolling_find_grass(peep))return; + + if (peep_update_patrolling_find_bin(peep))return; + + peep_update_patrolling_find_watering(peep); +} + +/* rct2: 0x0069030A */ +static void peep_update_walking(rct_peep* peep){ + if (!sub_68F3AE(peep))return; + + if (peep->flags & PEEP_FLAGS_WAVING){ + if (peep->action >= PEEP_ACTION_NONE_1){ + if ((0xFFFF & scenario_rand()) < 936){ + invalidate_sprite((rct_sprite*)peep); + + peep->action = PEEP_ACTION_WAVE_2; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + + sub_693B58(peep); + invalidate_sprite((rct_sprite*)peep); + } + } + } + + if (peep->flags & PEEP_FLAGS_PHOTO){ + if (peep->action >= PEEP_ACTION_NONE_1){ + if ((0xFFFF & scenario_rand()) < 936){ + invalidate_sprite((rct_sprite*)peep); + + peep->action = PEEP_ACTION_TAKE_PHOTO; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + + sub_693B58(peep); + invalidate_sprite((rct_sprite*)peep); + } + } + } + + if (peep->flags & PEEP_FLAGS_PAINTING){ + if (peep->action >= PEEP_ACTION_NONE_1){ + if ((0xFFFF & scenario_rand()) < 936){ + invalidate_sprite((rct_sprite*)peep); + + peep->action = PEEP_ACTION_DRAW_PICTURE; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + + sub_693B58(peep); + invalidate_sprite((rct_sprite*)peep); + } + } + } + + if (peep->flags & PEEP_FLAGS_LITTER){ + if (!(peep->next_var_29 & 0x18)){ + if ((0xFFFF & scenario_rand()) <= 4096){ + int ebp = (scenario_rand() & 0x3) + 2; + int x = peep->x + (scenario_rand() & 0x7) - 3; + int y = peep->y + (scenario_rand() & 0x7) - 3; + int direction = (scenario_rand() & 0x3); + + RCT2_CALLPROC_X(0x67375D, x, direction, y, peep->z, 0, 0, ebp); + } + } + } + else if (peep_has_empty_container(peep)){ + if ((!(peep->next_var_29 & 0x18)) && + ((peep->sprite_index & 0x1FF) == (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x1FF))&& + ((0xFFFF & scenario_rand()) <= 4096)){ + + uint8 pos_stnd = 0; + for (int container = peep_empty_container_standard_flag(peep); pos_stnd < 32; pos_stnd++)if (container&(1<item_standard_flags &= ~(1 << pos_stnd); + bp = RCT2_ADDRESS(0x97EFCC, uint8)[pos_stnd]; + } + else{ + uint8 pos_extr = 0; + for (int container = peep_empty_container_extra_flag(peep); pos_extr < 32; pos_extr++)if (container&(1 << pos_extr))break; + peep->item_extra_flags &= ~(1 << pos_extr); + bp = RCT2_ADDRESS(0x97EFE8, uint8)[pos_extr]; + } + + peep->var_45 |= 8; + peep_update_sprite_type(peep); + + int x = peep->x + (scenario_rand() & 0x7) - 3; + int y = peep->y + (scenario_rand() & 0x7) - 3; + int direction = (scenario_rand() & 0x3); + + RCT2_CALLPROC_X(0x67375D, x, direction, y, peep->z, 0, 0, bp); + } + } + + RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; + + if ((peep->next_var_29 & 0x18) == 8){ + rct_map_element* map_element = map_get_surface_element_at(peep->next_x / 32, peep->next_y / 32); + + int water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + if (water_height){ + invalidate_sprite((rct_sprite*)peep); + water_height *= 16; + sprite_move(peep->x, peep->y, water_height, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_FALLING; + peep_window_state_update(peep); + return; + } + } + + peep_check_if_lost(peep); + peep_check_cant_find_ride(peep); + peep_check_cant_find_exit(peep); + + if (peep_update_walking_find_bench(peep))return; + + if (peep_update_walking_find_bin(peep))return; + + peep_update_walking_break_scenery(peep); + + if (peep->state != PEEP_STATE_WALKING)return; + + if (peep->flags & PEEP_FLAGS_LEAVING_PARK)return; + + if (peep->nausea > 140)return; + + if (peep->happiness < 120)return; + + if (peep->bathroom > 140)return; + + uint16 chance = peep_has_food(peep) ? 13107 : 2849; + + if ((scenario_rand() & 0xFFFF) > chance)return; + + if (peep->next_var_29 & 0x1C)return; + + rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); + + for (;; map_element++){ + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){ + if (peep->next_z == map_element->base_height)break; + } + if (map_element_is_last_for_tile(map_element)){ + return; + } + } + + uint8 additions = map_element->properties.path.additions & 0xF; + + int ebp = 15; + + if (additions){ + if (!(map_element->properties.path.additions & 0x80)){ + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + + if (!(sceneryEntry->path_bit.var_06 & 0x2)) ebp = 9; + } + } + + int edges = (map_element->properties.path.edges & 0xF) ^ 0xF; + if (edges == 0) return; + + uint8 chosen_edge = scenario_rand() & 0x3; + + for (; !(edges & (1 << chosen_edge));)chosen_edge = (chosen_edge + 1) & 3; + + uint8 ride_to_view; + uint8 ride_seat_to_view; + { + int eax = chosen_edge, _ebx = 0, ecx, edx = 0, esi = (int)peep, _ebp = 0, edi = 0; + // Work out what to look at + if (RCT2_CALLFUNC_X(0x00690B99, &eax, &_ebx, &ecx, &edx, &esi, &edi, &_ebp) & 0x100)return; + + ride_to_view = ecx & 0xFF; + ride_seat_to_view = (ecx & 0xFF00) >> 8; + } + + uint16 sprite_id = RCT2_ADDRESS(0xF1EF60, uint16)[((peep->x & 0x1FE0) << 3) | (peep->y >> 5)]; + for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->unknown.next_in_quadrant){ + sprite = &g_sprite_list[sprite_id]; + + if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_PEEP)continue; + + if (sprite->peep.state != PEEP_STATE_WATCHING)continue; + + if (peep->z != sprite->peep.z)continue; + + if ((sprite->peep.var_37 & 0x3) != chosen_edge)continue; + + ebp &= ~(1 << ((sprite->peep.var_37 & 0x1C) >> 2)); + } + + if (!ebp)return; + + uint8 chosen_position = scenario_rand() & 0x3; + + for (; !(ebp & (1 << chosen_position));)chosen_position = (chosen_position + 1) & 3; + + peep->current_ride = ride_to_view; + peep->current_seat = ride_seat_to_view; + peep->var_37 = chosen_edge | (chosen_position << 2); + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_WATCHING; + peep_window_state_update(peep); + + peep->sub_state = 0; + + int ebx = peep->var_37 & 0x1F; + int x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x981F4C, uint16)[ebx * 2]; + int y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x981F4E, uint16)[ebx * 2]; + + peep->destination_x = x; + peep->destination_y = y; + peep->destination_tolerence = 3; + + if (peep->current_seat&1){ + peep_insert_new_thought(peep, PEEP_THOUGHT_NEW_RIDE, 0xFF); + } + if (peep->current_ride == 0xFF){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SCENERY, 0xFF); + } +} + /* From peep_update */ static void peep_update_thoughts(rct_peep* peep){ // Thoughts must always have a gap of at least @@ -1096,13 +4246,10 @@ static void peep_update_thoughts(rct_peep* peep){ */ static void peep_update(rct_peep *peep) { - //RCT2_CALLPROC_X(0x0068FC1E, 0, 0, 0, 0, (int)peep, 0, 0); return; - //return; - if (peep->type == PEEP_TYPE_GUEST) { - if (peep->var_AD != 255) - if (++peep->var_AE < 720) - peep->var_AD = 255; + if (peep->previous_ride != 255) + if (++peep->previous_ride_time_out >= 720) + peep->previous_ride = 255; peep_update_thoughts(peep); } @@ -1113,7 +4260,7 @@ static void peep_update(rct_peep *peep) stepsToTake = 95; if ((peep->flags & PEEP_FLAGS_SLOW_WALK) && peep->state != PEEP_STATE_QUEUING) stepsToTake /= 2; - if (peep->action == 255 && ((peep->next_z >> 8) & 4)) { + if (peep->action == 255 && (peep->next_var_29 & 4)) { stepsToTake /= 2; if (peep->state == PEEP_STATE_QUEUING) stepsToTake += stepsToTake / 2; @@ -1126,8 +4273,6 @@ static void peep_update(rct_peep *peep) RCT2_CALLPROC_X(0x0068FD3A, 0, 0, 0, 0, (int)peep, 0, 0); } else { // loc_68FD2F - //RCT2_CALLPROC_X(0x68FD2F, 0, 0, 0, 0, (int)peep, 0, 0); - //return; switch (peep->state) { case PEEP_STATE_FALLING: peep_update_falling(peep); @@ -1136,23 +4281,22 @@ static void peep_update(rct_peep *peep) peep_update_1(peep); break; case PEEP_STATE_QUEUING_FRONT: - peep_update_leaving_ride(peep); + peep_update_ride(peep); break; case PEEP_STATE_ON_RIDE: // No action break; case PEEP_STATE_LEAVING_RIDE: - peep_update_leaving_ride(peep); + peep_update_ride(peep); break; case PEEP_STATE_WALKING: - RCT2_CALLPROC_X(0x0069030A, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_walking(peep); break; case PEEP_STATE_QUEUING: peep_update_queuing(peep); break; case PEEP_STATE_ENTERING_RIDE: - // Calls the same function as leaving ride - peep_update_leaving_ride(peep); + peep_update_ride(peep); break; case PEEP_STATE_SITTING: peep_update_sitting(peep); @@ -1161,7 +4305,7 @@ static void peep_update(rct_peep *peep) peep_update_picked(peep); break; case PEEP_STATE_PATROLLING: - RCT2_CALLPROC_X(0x006BF1FD, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_patrolling(peep); break; case PEEP_STATE_MOWING: peep_update_mowing(peep); @@ -1176,13 +4320,13 @@ static void peep_update(rct_peep *peep) peep_update_leaving_park(peep); break; case PEEP_STATE_ANSWERING: - RCT2_CALLPROC_X(0x006C0CB8, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_answering(peep); break; case PEEP_STATE_FIXING: - RCT2_CALLPROC_X(0x006C0E8B, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_fixing(stepsToTake, peep); break; case PEEP_STATE_BUYING: - RCT2_CALLPROC_X(0x006912A3, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_buying(peep); break; case PEEP_STATE_WATCHING: peep_update_watching(peep); @@ -1190,21 +4334,21 @@ static void peep_update(rct_peep *peep) case PEEP_STATE_EMPTYING_BIN: peep_update_emptying_bin(peep); break; - case PEEP_STATE_20: - RCT2_CALLPROC_X(0x00691089, 0, 0, 0, 0, (int)peep, 0, 0); + case PEEP_STATE_USING_BIN: + peep_update_using_bin(peep); break; case PEEP_STATE_WATERING: peep_update_watering(peep); break; case PEEP_STATE_HEADING_TO_INSPECTION: - RCT2_CALLPROC_X(0x006C16D7, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_heading_to_inspect(peep); break; case PEEP_STATE_INSPECTING: - RCT2_CALLPROC_X(0x006C0E8B, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_fixing(stepsToTake, peep); break; //There shouldnt be any more default: - RCT2_CALLPROC_X(0x0068FD2F, 0, 0, 0, 0, (int)peep, 0, 0); + assert(0); break; } } @@ -1237,32 +4381,32 @@ void peep_problem_warnings_update() break; case PEEP_THOUGHT_TYPE_HUNGRY: // 0x14 - if (peep->guest_heading_to_ride_id == -1){ + if (peep->guest_heading_to_ride_id == 0xFF){ hunger_counter++; break; } ride = &g_ride_list[peep->guest_heading_to_ride_id]; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x80000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_FOOD)) hunger_counter++; break; case PEEP_THOUGHT_TYPE_THIRSTY: - if (peep->guest_heading_to_ride_id == -1){ + if (peep->guest_heading_to_ride_id == 0xFF){ thirst_counter++; break; } ride = &g_ride_list[peep->guest_heading_to_ride_id]; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x1000000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_DRINKS)) thirst_counter++; break; case PEEP_THOUGHT_TYPE_BATHROOM: - if (peep->guest_heading_to_ride_id == -1){ + if (peep->guest_heading_to_ride_id == 0xFF){ bathroom_counter++; break; } ride = &g_ride_list[peep->guest_heading_to_ride_id]; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x2000000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_BATHROOM)) bathroom_counter++; break; @@ -1412,7 +4556,10 @@ void peep_update_crowd_noise() // Load and play crowd noise #ifdef USE_MIXER if (!gCrowdSoundChannel) { - gCrowdSoundChannel = Mixer_Play_Music(PATH_ID_CSS2); + gCrowdSoundChannel = Mixer_Play_Music(PATH_ID_CSS2, MIXER_LOOP_INFINITE, false); + if (gCrowdSoundChannel) { + Mixer_Channel_SetGroup(gCrowdSoundChannel, MIXER_GROUP_NONE); + } } if (gCrowdSoundChannel) { Mixer_Channel_Volume(gCrowdSoundChannel, DStoMixerVolume(volume)); @@ -1454,10 +4601,10 @@ void peep_applause() // Release balloon if (peep->item_standard_flags & PEEP_ITEM_BALLOON) { peep->item_standard_flags &= ~PEEP_ITEM_BALLOON; - if (peep->x != 0x8000) { - create_balloon(peep->x, peep->y, peep->z + 9, peep->balloon_colour); + if (peep->x != (sint16)0x8000) { + create_balloon(peep->x, peep->y, peep->z + 9, peep->balloon_colour, 0); peep->var_45 |= 8; - RCT2_CALLPROC_X(0x0069B8CC, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_sprite_type(peep); } } @@ -1465,7 +4612,7 @@ void peep_applause() if ((peep->state == PEEP_STATE_WALKING || peep->state == PEEP_STATE_QUEUING) && peep->action >= 254) { peep->action = PEEP_ACTION_CLAP; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); } @@ -1475,18 +4622,174 @@ void peep_applause() sound_play_panned(SOUND_APPLAUSE, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2, 0, 0, 0); } +/** +* +* rct2: 0x0069C35E +*/ +void peep_update_days_in_queue() +{ + uint16 sprite_index; + rct_peep *peep; + + FOR_ALL_GUESTS(sprite_index, peep) { + if (peep->var_2A == 0 && peep->state == PEEP_STATE_QUEUING) { + if (peep->days_in_queue < 255) { + peep->days_in_queue += 1; + } + } + } +} + /** * * rct2: 0x0069A05D */ rct_peep *peep_generate(int x, int y, int z) { - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ecx = y; - edx = z; - RCT2_CALLFUNC_X(0x0069A05D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return (rct_peep*)esi; + if (RCT2_GLOBAL(0x13573C8, uint16) < 400) + return NULL; + + rct_peep* peep = (rct_peep*)create_sprite(1); + + move_sprite_to_list((rct_sprite*)peep, SPRITE_LINKEDLIST_OFFSET_PEEP); + + peep->sprite_identifier = 1; + peep->sprite_type = 0; + peep->var_2A = 1; + peep->state = PEEP_STATE_FALLING; + peep->action = PEEP_ACTION_NONE_2; + peep->var_6D = 0; + peep->action_sprite_image_offset = 0; + peep->no_action_frame_no = 0; + peep->action_sprite_type = 0; + peep->flags = 0; + peep->favourite_ride = 0xFF; + peep->var_FA = 0; + + uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2]; + peep->sprite_width = edx[peep->action_sprite_type * 4]; + peep->sprite_height_negative = edx[peep->action_sprite_type * 4 + 1]; + peep->sprite_height_positive = edx[peep->action_sprite_type * 4 + 2]; + + peep->sprite_direction = 0; + + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite((rct_sprite*)peep); + + peep->var_41 = (scenario_rand() & 0x1F) + 45; + peep->var_C4 = 0; + peep->var_79 = 0xFF; + peep->type = PEEP_TYPE_GUEST; + peep->previous_ride = 0xFF; + peep->thoughts->type = PEEP_THOUGHT_TYPE_NONE; + peep->var_45 = 0; + + uint8 al = (scenario_rand() & 0x7) + 3; + uint8 ah = min(al, 7) - 3; + + if (al >= 7) al = 15; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_LESS_INTENSE_RIDES){ + ah = 0; + al = 4; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_MORE_INTENSE_RIDES){ + ah = 9; + al = 15; + } + + peep->intensity = (al << 4) | ah; + + uint8 nausea_tolerance = scenario_rand() & 0x7; + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_MORE_INTENSE_RIDES){ + nausea_tolerance += 4; + } + + peep->nausea_tolerance = RCT2_ADDRESS(0x009823A0, uint8)[nausea_tolerance]; + + sint8 happiness = (scenario_rand() & 0x1F) - 15 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8); + + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) == 0) + happiness += 0x80; + + peep->happiness = happiness; + peep->happiness_growth_rate = happiness; + peep->nausea = 0; + peep->nausea_growth_rate = 0; + + sint8 hunger = (scenario_rand() & 0x1F) - 15 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8); + + peep->hunger = hunger; + + sint8 thirst = (scenario_rand() & 0x1F) - 15 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8); + + peep->thirst = thirst; + + peep->bathroom = 0; + peep->var_42 = 0; + memset(&peep->rides_been_on, 0, 32); + + peep->no_of_rides = 0; + memset(&peep->var_48, 0, 16); + peep->id = RCT2_GLOBAL(0x013B0E6C, uint32)++; + peep->name_string_idx = 767; + + money32 cash = (scenario_rand() & 0x3) * 100 - 100 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16); + if (cash < 0) cash = 0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) == 0){ + cash = 500; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + cash = 0; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) == 0xFFFF){ + cash = 0; + } + + peep->cash_in_pocket = cash; + peep->cash_spent = 0; + peep->time_in_park = -1; + peep->var_CC = 0xFFFF; + peep->item_standard_flags = 0; + peep->item_extra_flags = 0; + peep->guest_heading_to_ride_id = 0xFF; + peep->var_E1 = 0; + peep->var_E3 = 0; + peep->var_EF = 0; + peep->paid_to_enter = 0; + peep->paid_on_rides = 0; + peep->paid_on_food = 0; + peep->paid_on_drink = 0; + peep->paid_on_souvenirs = 0; + peep->no_of_food = 0; + peep->no_of_drinks = 0; + peep->no_of_souvenirs = 0; + peep->var_F2 = 0; + peep->var_F3 = 0; + peep->var_F4 = 0; + + uint8 tshirt_colour = scenario_rand() % 33; + peep->tshirt_colour = RCT2_ADDRESS(0x009823D5, uint8)[tshirt_colour]; + + uint8 trousers_colour = scenario_rand() % 25; + peep->trousers_colour = RCT2_ADDRESS(0x009823BC, uint8)[trousers_colour]; + + uint8 energy = (scenario_rand() & 0x3F) + 65; + peep->energy = energy; + peep->energy_growth_rate = energy; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES){ + RCT2_CALLPROC_X(0x0069C483, 0, 0, 0, 0, (int)peep, 0, 0); + } + RCT2_CALLPROC_X(0x00699115, 0, 0, 0, 0, (int)peep, 0, 0); + + RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)++; + + return peep; } /** @@ -1513,9 +4816,8 @@ void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argum case PEEP_STATE_ENTERING_RIDE: *argument_1 = STR_ON_RIDE; ride = g_ride_list[peep->current_ride]; - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride.type * 8, uint32) & 0x400000){ + if (ride_type_has_flag(ride.type, RIDE_TYPE_FLAG_IN_RIDE)) *argument_1 = STR_IN_RIDE; - } *argument_1 |= (ride.name << 16); *argument_2 = ride.name_arguments; break; @@ -1525,7 +4827,7 @@ void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argum *argument_2 = ride.name_arguments; break; case PEEP_STATE_WALKING: - case PEEP_STATE_20: + case PEEP_STATE_USING_BIN: if (peep->guest_heading_to_ride_id != 0xFF){ ride = g_ride_list[peep->guest_heading_to_ride_id]; *argument_1 = STR_HEADING_FOR | (ride.name << 16); @@ -1588,11 +4890,11 @@ void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argum *argument_2 = 0; break; case PEEP_STATE_ANSWERING: - if (peep->var_2C == 0){ + if (peep->sub_state == 0){ *argument_1 = STR_WALKING; *argument_2 = 0; } - else if (peep->var_2C == 1){ + else if (peep->sub_state == 1){ *argument_1 = STR_ANSWERING_RADIO_CALL; *argument_2 = 0; } @@ -1800,11 +5102,8 @@ int peep_is_mechanic(rct_peep *peep) ); } -/* To simplify check of 0x36BA3E0 and 0x11FF78 - * returns 0 on no food. - */ -int peep_has_food(rct_peep* peep){ - return (peep->item_standard_flags &( +static int peep_has_food_standard_flag(rct_peep* peep){ + return peep->item_standard_flags &( PEEP_ITEM_DRINK | PEEP_ITEM_BURGER | PEEP_ITEM_FRIES | @@ -1818,8 +5117,11 @@ int peep_has_food(rct_peep* peep){ PEEP_ITEM_DONUT | PEEP_ITEM_COFFEE | PEEP_ITEM_CHICKEN | - PEEP_ITEM_LEMONADE)) || - (peep->item_extra_flags &( + PEEP_ITEM_LEMONADE); +} + +static int peep_has_food_extra_flag(rct_peep* peep){ + return peep->item_extra_flags &( PEEP_ITEM_PRETZEL | PEEP_ITEM_CHOCOLATE | PEEP_ITEM_ICED_TEA | @@ -1834,7 +5136,61 @@ int peep_has_food(rct_peep* peep){ PEEP_ITEM_SUB_SANDWICH | PEEP_ITEM_COOKIE | PEEP_ITEM_ROAST_SAUSAGE - )); + ); +} + +/* To simplify check of 0x36BA3E0 and 0x11FF78 + * returns 0 on no food. + */ +int peep_has_food(rct_peep* peep){ + return peep_has_food_standard_flag(peep) || + peep_has_food_extra_flag(peep); +} + +static int peep_empty_container_standard_flag(rct_peep* peep){ + return peep->item_standard_flags &( + PEEP_ITEM_EMPTY_CAN | + PEEP_ITEM_EMPTY_BURGER_BOX | + PEEP_ITEM_EMPTY_CUP | + PEEP_ITEM_RUBBISH | + PEEP_ITEM_EMPTY_BOX | + PEEP_ITEM_EMPTY_BOTTLE + ); +} + +static int peep_empty_container_extra_flag(rct_peep* peep){ + return peep->item_extra_flags &( + PEEP_ITEM_EMPTY_BOWL_RED | + PEEP_ITEM_EMPTY_DRINK_CARTON | + PEEP_ITEM_EMPTY_JUICE_CUP | + PEEP_ITEM_EMPTY_BOWL_BLUE + ); +} + +static int peep_has_empty_container(rct_peep* peep){ + return peep_empty_container_standard_flag(peep) || + peep_empty_container_extra_flag(peep); +} + +/* Simplifies 0x690582. Returns 1 if should find bench*/ +static int peep_should_find_bench(rct_peep* peep){ + if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK)){ + if (peep_has_food(peep)){ + if (peep->hunger < 128 || peep->happiness < 128){ + if (!(peep->next_var_29 & 0x1C)){ + return 1; + } + } + } + if (peep->nausea <= 170 && peep->energy > 50){ + return 0; + } + + if (!(peep->next_var_29 & 0x1C)){ + return 1; + } + } + return 0; } /** @@ -1844,12 +5200,12 @@ int peep_has_food(rct_peep* peep){ * esi: peep */ void peep_insert_new_thought(rct_peep *peep, uint8 thought_type, uint8 thought_arguments){ - int action = RCT2_ADDRESS(0x981DB0, uint16)[thought_type]; + uint8 action = RCT2_ADDRESS(0x981DB0, uint16)[thought_type] & 0xFF; if (action != 0xFF && peep->action >= 254){ peep->action = action; peep->action_frame = 0; - peep->var_70 = 0; + peep->action_sprite_image_offset = 0; sub_693B58(peep); invalidate_sprite((rct_sprite*)peep); } @@ -1878,6 +5234,45 @@ void peep_insert_new_thought(rct_peep *peep, uint8 thought_type, uint8 thought_a peep->var_45 |= (1 << 0); } +/* rct2: 0x00699FE3 + * Stops peeps that are having thoughts + * such as "I'm hungry" after visiting a food shop. + * Works for Thirst/Hungry/Low Money/Bathroom + */ +static void peep_stop_purchase_thought(rct_peep* peep, uint8 ride_type){ + + uint8 thought_type = PEEP_THOUGHT_TYPE_HUNGRY; + + if (!(RCT2_ADDRESS(0x97CF40, uint32)[ride_type * 2] & 0x800000)){ + thought_type = PEEP_THOUGHT_TYPE_THIRSTY; + if (!(RCT2_ADDRESS(0x97CF40, uint32)[ride_type * 2] & 0x1000000)){ + thought_type = PEEP_THOUGHT_RUNNING_OUT; + if (ride_type != RIDE_TYPE_CASH_MACHINE){ + thought_type = PEEP_THOUGHT_TYPE_BATHROOM; + if (!(RCT2_ADDRESS(0x97CF40, uint32)[ride_type * 2] & 0x2000000)){ + return; + } + } + } + } + + //Remove the related thought + for (int i = 0; i < PEEP_MAX_THOUGHTS; ++i){ + rct_peep_thought* thought = &peep->thoughts[i]; + + if (thought->type == PEEP_THOUGHT_TYPE_NONE) break; + + if (thought->type != thought_type)continue; + + memmove(thought, thought + 1, sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1)); + + peep->thoughts[PEEP_MAX_THOUGHTS - 1].type = PEEP_THOUGHT_TYPE_NONE; + + peep->var_45 |= (1 << 0); + i--; + } +} + void peep_set_map_tooltip(rct_peep *peep) { if (peep->type == PEEP_TYPE_GUEST) { @@ -1900,4 +5295,19 @@ void peep_set_map_tooltip(rct_peep *peep) RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 8, uint32) = arg0; RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 12, uint32) = arg1; } -} \ No newline at end of file +} + + +void sub_693BAB(rct_peep* peep) { + uint8 bl = peep->var_6F; + if (bl != peep->action_sprite_type) { + invalidate_sprite((rct_sprite*)peep); + peep->action_sprite_type = bl; + uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2]; + peep->sprite_width = edx[bl * 4]; + peep->sprite_height_negative = edx[bl * 4 + 1]; + peep->sprite_height_positive = edx[bl * 4 + 2]; + invalidate_sprite((rct_sprite*)peep); + } +} + diff --git a/src/peep/peep.h b/src/peep/peep.h index 2a93663327..837590b826 100644 --- a/src/peep/peep.h +++ b/src/peep/peep.h @@ -202,14 +202,16 @@ enum PEEP_STATE { PEEP_STATE_BUYING = 17, PEEP_STATE_WATCHING = 18, PEEP_STATE_EMPTYING_BIN = 19, - PEEP_STATE_20 = 20, + PEEP_STATE_USING_BIN = 20, PEEP_STATE_WATERING = 21, PEEP_STATE_HEADING_TO_INSPECTION = 22, PEEP_STATE_INSPECTING = 23 }; enum PEEP_ACTION_EVENTS { - PEEP_ACTION_CHECK_WATCH = 1, + PEEP_ACTION_CHECK_TIME = 0, + // If no food then check watch + PEEP_ACTION_EAT_FOOD = 1, PEEP_ACTION_SHAKE_HEAD = 2, PEEP_ACTION_EMPTY_POCKETS = 3, PEEP_ACTION_SITTING_EAT_FOOD = 4, @@ -230,9 +232,14 @@ enum PEEP_ACTION_EVENTS { PEEP_ACTION_STAFF_WATERING = 19, PEEP_ACTION_WAVE = 22, PEEP_ACTION_STAFF_EMPTY_BIN = 23, + PEEP_ACTION_WAVE_2 = 24, PEEP_ACTION_TAKE_PHOTO = 25, PEEP_ACTION_CLAP = 26, + PEEP_ACTION_DRAW_PICTURE = 28, + + PEEP_ACTION_WITHDRAW_MONEY = 30, + PEEP_ACTION_NONE_1 = 254, PEEP_ACTION_NONE_2 = 255 }; @@ -258,9 +265,13 @@ enum PEEP_FLAGS { PEEP_FLAGS_EATING = (1 << 17), // Reduces hunger PEEP_FLAGS_EXPLODE = (1 << 18), + PEEP_FLAGS_21 = (1<<21), + PEEP_FLAGS_JOY = (1 << 23), // Makes the peep jump in joy PEEP_FLAGS_ANGRY = (1 << 24), - PEEP_FLAGS_ICE_CREAM = (1 << 25) // Unconfirmed + PEEP_FLAGS_ICE_CREAM = (1 << 25), // Unconfirmed + + PEEP_FLAGS_TWITCH = (1 << 31) // Added for twitch integration }; enum PEEP_NAUSEA_TOLERANCE { @@ -336,18 +347,21 @@ typedef struct { typedef struct { uint8 sprite_identifier; // 0x00 uint8 var_01; - uint16 var_02; // 0x02 + uint16 next_in_quadrant; // 0x02 uint16 next; // 0x04 uint16 previous; // 0x06 uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... - uint8 var_09; // 0x09 + // Height from center of sprite to bottom + uint8 sprite_height_negative; // 0x09 uint16 sprite_index; // 0x0A uint16 var_0C; sint16 x; // 0x0E sint16 y; // 0x10 sint16 z; // 0x12 - uint8 var_14; // 0x14 - uint8 var_15; // 0x15 + // Width from center of sprite to edge + uint8 sprite_width; // 0x14 + // Height from center of sprite to top + uint8 sprite_height_positive; // 0x15 sint16 sprite_left; // 0x16 sint16 sprite_top; // 0x18 sint16 sprite_right; // 0x1A @@ -357,10 +371,11 @@ typedef struct { uint16 name_string_idx; // 0x22 uint16 next_x; // 0x24 uint16 next_y; // 0x26 - uint16 next_z; // 0x28 possibly split into two uint8s + uint8 next_z; // 0x28 + uint8 next_var_29; // 0x29 uint8 var_2A; uint8 state; // 0x2B - uint8 var_2C; + uint8 sub_state; // 0x2C uint8 sprite_type; // 0x2D uint8 type; // 0x2E union{ @@ -376,18 +391,19 @@ typedef struct { uint8 energy; // 0x38 uint8 energy_growth_rate; // 0x39 uint8 happiness; // 0x3A - sint8 happiness_growth_rate; // 0x3B + uint8 happiness_growth_rate; // 0x3B uint8 nausea; // 0x3C uint8 nausea_growth_rate; // 0x3D uint8 hunger; // 0x3E uint8 thirst; // 0x3F uint8 bathroom; // 0x40 - uint8 pad_41[0x2]; + uint8 var_41; + uint8 var_42; uint8 intensity; // 0x43 uint8 nausea_tolerance; // 0x44 uint8 var_45; // Some sort of flags? money16 paid_on_drink; // 0x46 - uint8 pad_48[0x10]; + uint8 var_48[16]; uint32 item_extra_flags; // 0x58 uint8 photo2_ride_ref; // 0x5C uint8 photo3_ride_ref; // 0x5D @@ -398,28 +414,34 @@ typedef struct { uint8 current_train; // 0x6A union{ struct{ - uint8 current_car; // 0x6B - uint8 current_seat; // 0x6C + uint8 current_car; // 0x6B + uint8 current_seat; // 0x6C }; - uint16 time_to_sitdown; //0x6B + uint16 time_to_sitdown; //0x6B struct{ uint8 time_to_stand; //0x6B uint8 standing_flags; //0x6C }; }; uint8 var_6D; // 0x6D - uint8 var_6E; // 0x6E + uint8 action_sprite_type; // 0x6E uint8 var_6F; - uint8 var_70; + uint8 action_sprite_image_offset; // 0x70 uint8 action; // 0x71 uint8 action_frame; // 0x72 uint8 var_73; - uint16 var_74; + union { + uint16 var_74; // time getting to ride to fix + uint16 next_in_queue; // 0x74 + }; uint8 var_76; uint8 pad_77; - uint8 var_78; - uint8 pad_79; - uint16 var_7A; // time waiting in line possibly + union{ + uint8 maze_last_edge; // 0x78 + uint8 var_78; + }; + uint8 var_79; + uint16 time_in_queue; // 0x7A uint8 rides_been_on[32]; // 0x7C // 255 bit bitmap of every ride the peep has been on see // window_peep_rides_update for how to use. @@ -427,9 +449,9 @@ typedef struct { money32 cash_in_pocket; // 0xA0 money32 cash_spent; // 0xA4 sint32 time_in_park; // 0xA8 - uint8 var_AC; // 0xAC - uint8 var_AD; // creation/hire time? - uint16 var_AE; + sint8 var_AC; // 0xAC + uint8 previous_ride; // 0xAD + uint16 previous_ride_time_out; // 0xAE rct_peep_thought thoughts[PEEP_MAX_THOUGHTS]; // 0xB0 uint8 var_C4; // 0xC4 union // 0xC5 @@ -445,10 +467,10 @@ typedef struct { uint32 flags; // 0xC8 uint32 var_CC; uint8 pad_D0[0x10]; - uint8 var_E0; // 0xE0 - uint8 pad_E1; + uint8 no_action_frame_no; // 0xE0 + uint8 var_E1; uint8 var_E2; // 0xE2 - uint8 pad_E3; + uint8 var_E3; union{ money16 paid_to_enter; // 0xE4 uint16 staff_lawns_mown; // 0xE4 @@ -470,17 +492,19 @@ typedef struct { uint8 no_of_food; // 0xEC uint8 no_of_drinks; // 0xED uint8 no_of_souvenirs; // 0xEE - uint8 pad_EF; + uint8 var_EF; uint8 voucher_type; // 0xF0 uint8 voucher_arguments; // 0xF1 ride_id or string_offset_id - uint8 pad_F2; + uint8 var_F2; uint8 var_F3; - uint8 pad_F4[0x02]; + uint8 var_F4; + uint8 days_in_queue; // 0xF5 uint8 balloon_colour; // 0xF6 uint8 umbrella_colour; // 0xF7 uint8 hat_colour; // 0xF8 uint8 favourite_ride; // 0xF9 - uint16 pad_FA; + uint8 var_FA; + uint8 pad_FB; uint32 item_standard_flags; // 0xFC } rct_peep; @@ -537,6 +561,7 @@ int peep_can_be_picked_up(rct_peep* peep); void peep_update_all(); void peep_problem_warnings_update(); void peep_update_crowd_noise(); +void peep_update_days_in_queue(); void peep_applause(); rct_peep *peep_generate(int x, int y, int z); void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argument_2); @@ -547,6 +572,8 @@ int peep_check_easteregg_name(int index, rct_peep *peep); int peep_get_easteregg_name_id(rct_peep *peep); int peep_is_mechanic(rct_peep *peep); int peep_has_food(rct_peep* peep); +void peep_sprite_remove(rct_peep* peep); +void peep_remove(rct_peep* peep); void peep_window_state_update(rct_peep* peep); void peep_decrement_num_riders(rct_peep* peep); @@ -560,5 +587,7 @@ void peep_insert_new_thought(rct_peep *peep, uint8 thought_type, uint8 thought_a void peep_set_map_tooltip(rct_peep *peep); void sub_693B58(rct_peep* peep); +void remove_peep_from_ride(rct_peep* peep); +void remove_peep_from_queue(rct_peep* peep); #endif diff --git a/src/peep/staff.c b/src/peep/staff.c index 5426dbdcdb..f6fa857107 100644 --- a/src/peep/staff.c +++ b/src/peep/staff.c @@ -19,7 +19,9 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" +#include "../scenario.h" #include "../interface/viewport.h" #include "../localisation/string_ids.h" #include "../management/finance.h" @@ -28,38 +30,23 @@ #include "staff.h" /** -* -* rct2: 0x00669E55 -*/ -void game_command_update_staff_colour() + * + * rct2: 0x00669E55 + */ +void game_command_update_staff_colour(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) { - uint8 staff_type, colour, _bl; + uint8 staffType, colour; int spriteIndex; rct_peep *peep; - #ifdef _MSC_VER - __asm mov _bl, bl - #else - __asm__("mov %[_bl], bl " : [_bl] "+m" (_bl)); - #endif + staffType = (*ebx >> 8) & 0xFF; + colour = (*edx >> 8) & 0xFF; - #ifdef _MSC_VER - __asm mov staff_type, bh - #else - __asm__("mov %[staff_type], bh " : [staff_type] "+m" (staff_type)); - #endif - - #ifdef _MSC_VER - __asm mov colour, dh - #else - __asm__("mov %[colour], bh " : [colour] "+m" (colour)); - #endif - - if (_bl & 1) { - RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[staff_type] = colour; + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[staffType] = colour; FOR_ALL_PEEPS(spriteIndex, peep) { - if (peep->type == PEEP_TYPE_STAFF && peep->staff_type == staff_type) { + if (peep->type == PEEP_TYPE_STAFF && peep->staff_type == staffType) { peep->tshirt_colour = colour; peep->trousers_colour = colour; } @@ -67,31 +54,25 @@ void game_command_update_staff_colour() } gfx_invalidate_screen(); - - #ifdef _MSC_VER - __asm mov ebx, 0 - #else - __asm__("mov ebx, 0 "); - #endif + *ebx = 0; } /** -* -* rct2: 0x006BEFA1 -*/ -void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, - int* esi, int* edi, int* ebp) + * + * rct2: 0x006BEFA1 + */ +void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { uint8 _bl = *ebx & 0xFF, staff_type = (*ebx & 0xFF00) >> 8; uint16 _ax = *eax & 0xFFFF, _cx = *ecx & 0xFFFF, _dx = *edx & 0xFFFF; - RCT2_GLOBAL(0x0141F56C, uint8) = 0x28; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_WAGES * 4; RCT2_GLOBAL(0x009DEA5E, uint16) = _ax; RCT2_GLOBAL(0x009DEA60, uint16) = _cx; RCT2_GLOBAL(0x009DEA62, uint16) = _dx; if (RCT2_GLOBAL(0x13573C8, uint16) < 0x190) { - *ebx = 0x80000000; + *ebx = MONEY32_UNDEFINED; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TOO_MANY_PEOPLE_IN_GAME; return; } @@ -103,7 +84,7 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, } if (i == STAFF_MAX_COUNT) { - *ebx = 0x80000000; + *ebx = MONEY32_UNDEFINED; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TOO_MANY_STAFF_IN_GAME; return; } @@ -117,36 +98,23 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, if (newPeep == NULL) { - *ebx = 0x80000000; + *ebx = MONEY32_UNDEFINED; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TOO_MANY_PEOPLE_IN_GAME; return; } if (_bl == 0) { - RCT2_CALLPROC_X(0x0069EDB6, 0, 0, _ecx, 0, (int)newPeep, 0, 0); - } - else { + sprite_remove((rct_sprite*)newPeep); + } else { move_sprite_to_list((rct_sprite *)newPeep, SPRITE_LINKEDLIST_OFFSET_PEEP); - + newPeep->sprite_identifier = 1; - newPeep->var_09 = 0x0F; - newPeep->var_15 = 5; - newPeep->var_14 = 8; - newPeep->sprite_direction = 0; - - sprite_move(_ax, *ecx, _dx, (rct_sprite*)newPeep); - - newPeep->state = PEEP_STATE_PICKED; - if (newPeep->x != -32768) { - newPeep->state = 0; - } - newPeep->var_45 = 0; - newPeep->action = 0xFF; + newPeep->action = PEEP_ACTION_NONE_2; newPeep->var_6D = 0; - newPeep->var_70 = 0; - newPeep->var_E0 = 0; - newPeep->var_6E = 0; + newPeep->action_sprite_image_offset = 0; + newPeep->no_action_frame_no = 0; + newPeep->action_sprite_type = 0; newPeep->var_C4 = 0; newPeep->type = PEEP_TYPE_STAFF; newPeep->var_2A = 0; @@ -164,8 +132,6 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, newPeep->var_C6 = 3; } - newPeep->staff_type = 0xFF; - uint16 idSearchSpriteIndex; rct_peep* idSearchPeep; @@ -198,14 +164,86 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, newPeep->sprite_type = _eax; _edx = RCT2_ADDRESS(0x0098270C, uint32)[_eax * 2]; - newPeep->var_14 = *((uint8*)_edx); - newPeep->var_09 = *((uint8*)(_edx + 1)); - newPeep->var_15 = *((uint8*)(_edx + 2)); + newPeep->sprite_width = *((uint8*)_edx); + newPeep->sprite_height_negative = *((uint8*)(_edx + 1)); + newPeep->sprite_height_positive = *((uint8*)(_edx + 2)); - sprite_move( newPeep->x, newPeep->y, newPeep->z, (rct_sprite*)newPeep); - invalidate_sprite((rct_sprite*)newPeep); + if ((gConfigGeneral.auto_staff_placement != 0) != ((SDL_GetModState() & KMOD_SHIFT) != 0)) { + newPeep->state = PEEP_STATE_FALLING; - newPeep->var_AD = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint8); + sint16 x, y, z; + uint32 count = 0; + uint16 sprite_index; + rct_peep *guest; + + FOR_ALL_GUESTS(sprite_index, guest) + if (guest->state == PEEP_STATE_WALKING) ++count; + + if (count == 0) { + count = 0; + uint8 i; + for (i = 0; i < 4; ++i) { + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] != SPRITE_LOCATION_NULL) ++count; + } + + if (count > 0) { + uint32 max = ((uint32)0xFFFFFFFF) - (((uint32)0xFFFFFFFF) % count) - 1; + if (max + count == 0) max = ((uint32)0xFFFFFFFF); + uint32 rand; + do { + rand = scenario_rand(); + } while (rand > max); + rand %= count; + + for (i = 0; i < 4; ++i) { + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] != SPRITE_LOCATION_NULL) { + if (rand == 0) break; + --rand; + } + } + + uint8 dir = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[i]; + x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[i]; + y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[i]; + z = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, sint16)[i]; + x += 16 + ((dir & 1) == 0 ? ((dir & 2) ? 32 : -32) : 0); + y += 16 + ((dir & 1) == 1 ? ((dir & 2) ? -32 : 32) : 0); + } else { + newPeep->state = PEEP_STATE_PICKED; + x = newPeep->x; + y = newPeep->y; + z = newPeep->z; + } + } else { + uint32 max = ((uint32)0xFFFFFFFF) - (((uint32)0xFFFFFFFF) % count) - 1; + if (max + count == 0) max = ((uint32)0xFFFFFFFF); + uint32 rand; + do { + rand = scenario_rand(); + } while (rand > max); + rand %= count; + + FOR_ALL_GUESTS(sprite_index, guest) + if (guest->state == PEEP_STATE_WALKING) { + if (rand == 0) break; + --rand; + } + + x = guest->x; + y = guest->y; + z = guest->z; + } + + sprite_move(x, y, z + 16, (rct_sprite*)newPeep); + invalidate_sprite((rct_sprite*)newPeep); + } else { + newPeep->state = PEEP_STATE_PICKED; + + sprite_move(newPeep->x, newPeep->y, newPeep->z, (rct_sprite*)newPeep); + invalidate_sprite((rct_sprite*)newPeep); + } + + newPeep->time_in_park = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); newPeep->var_CC = 0xFFFFFFFF; uint8 colour = RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[staff_type > 2 ? 2 : staff_type]; @@ -233,58 +271,144 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, *edi = newPeep->sprite_index; } +/** + * + * rct2: 0x006C0BB5 + */ +void game_command_set_staff_order(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 40; + uint8 order_id = *ebx >> 8; + uint16 sprite_id = *edx; + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + rct_peep *peep = &g_sprite_list[sprite_id].peep; + if(order_id & 0x80){ // change costume + uint8 sprite_type = order_id & ~0x80; + sprite_type += 4; + peep->sprite_type = sprite_type; + peep->flags &= ~PEEP_FLAGS_SLOW_WALK; + if(RCT2_ADDRESS(0x00982134, uint8)[sprite_type] & 1){ + peep->flags |= PEEP_FLAGS_SLOW_WALK; + } + peep->action_frame = 0; + sub_693B58(peep); + invalidate_sprite((rct_sprite*)peep); + window_invalidate_by_number(WC_PEEP, sprite_id); + window_invalidate_by_class(WC_STAFF_LIST); + }else{ + peep->staff_orders = order_id; + window_invalidate_by_number(WC_PEEP, sprite_id); + window_invalidate_by_class(WC_STAFF_LIST); + } + } + *ebx = 0; +} + +/** + * + * rct2: 0x006C09D1 + */ +void game_command_set_staff_patrol(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + int x = *eax; + int y = *ecx; + uint16 sprite_id = *edx; + rct_peep *peep = &g_sprite_list[sprite_id].peep; + int patrolOffset = peep->staff_id * (64 * 64 / 8); + int patrolIndex = ((x & 0x1F80) >> 7) | ((y & 0x1F80) >> 1); + int mask = 1 << (patrolIndex & 0x1F); + int base = patrolIndex >> 5; + + uint32 *patrolBits = (uint32*)(0x013B0E72 + patrolOffset + (base * 4)); + *patrolBits ^= mask; + + int ispatrolling = 0; + for(int i = 0; i < 128; i++){ + ispatrolling |= *(uint32*)(0x013B0E72 + patrolOffset + (i * 4)); + } + + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] &= ~2; + if(ispatrolling){ + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] |= 2; + } + + for(int y2 = 0; y2 < 4; y2++){ + for(int x2 = 0; x2 < 4; x2++){ + map_invalidate_tile_full((x & 0x1F80) + (x2 * 32), (y & 0x1F80) + (y2 * 32)); + } + } + staff_update_greyed_patrol_areas(); + } + *ebx = 0; +} + +/** + * + * rct2: 0x006C0B83 + */ +void game_command_fire_staff_member(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 40; + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + window_close_by_class(WC_FIRE_PROMPT); + uint16 sprite_id = *edx; + rct_peep *peep = &g_sprite_list[sprite_id].peep; + remove_peep_from_ride(peep); + peep_sprite_remove(peep); + } + *ebx = 0; +} + /* * Updates the colour of the given staff type. -*/ -void update_staff_colour(uint8 staff_type, uint16 colour) + */ +void update_staff_colour(uint8 staffType, uint16 colour) { - game_do_command( - 0, - (staff_type << 8) + 1, - 0, - (colour << 8) + 4, - GAME_COMMAND_SET_STAFF_COLOUR, - 0, - 0); + game_do_command(0, (staffType << 8) | GAME_COMMAND_FLAG_APPLY, 0, (colour << 8) | 4, GAME_COMMAND_SET_STAFF_COLOUR, 0, 0); } /* * Hires a new staff member of the given type. If the hire cannot be completed (eg. the maximum * number of staff is reached or there are too many people in the game) it returns 0xFFFF. -*/ -uint16 hire_new_staff_member(uint8 staff_type) + */ +uint16 hire_new_staff_member(uint8 staffType) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_HIRE_NEW_STAFF; int eax, ebx, ecx, edx, esi, edi, ebp; eax = 0x8000; - ebx = staff_type << 8 | 1; + ebx = staffType << 8 | GAME_COMMAND_FLAG_APPLY; int result = game_do_command_p(GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (result == 0x80000000) + if (result == MONEY32_UNDEFINED) return 0xFFFF; return edi; } -void sub_6C0C3F() +/** + * + * rct2: 0x006C0C3F + */ +void staff_update_greyed_patrol_areas() { - register rct_peep* peep; + rct_peep* peep; - for (register uint8 staff_type = 0; staff_type < STAFF_TYPE_COUNT; ++staff_type) + for (int staff_type = 0; staff_type < STAFF_TYPE_COUNT; ++staff_type) { - for (register uint8 i = 0; i < 128; ++i) - RCT2_ADDRESS(0x13B0E72 + (staff_type + STAFF_MAX_COUNT) * 512, uint32)[i] = 0; + for (int i = 0; i < 128; ++i) + RCT2_ADDRESS(0x13B0E72 + ((staff_type + STAFF_MAX_COUNT) * 512), uint32)[i] = 0; - for (register uint16 sprite_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16); sprite_index != SPRITE_INDEX_NULL; sprite_index = peep->next) + for (uint16 sprite_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16); sprite_index != SPRITE_INDEX_NULL; sprite_index = peep->next) { peep = GET_PEEP(sprite_index); if (peep->type == PEEP_TYPE_STAFF && staff_type == peep->staff_type) { - for (register uint8 i = 0; i < 128; ++i) - RCT2_ADDRESS(0x13B0E72 + (staff_type + STAFF_MAX_COUNT) * 512, uint32)[i] |= RCT2_ADDRESS(0x13B0E72 + (peep->staff_id * 512) * 512, uint32)[i]; + for (int i = 0; i < 128; ++i) + RCT2_ADDRESS(0x13B0E72 + ((staff_type + STAFF_MAX_COUNT) * 512), uint32)[i] |= RCT2_ADDRESS(0x13B0E72 + (peep->staff_id * 512), uint32)[i]; } } @@ -312,7 +436,7 @@ int staff_is_location_in_patrol_area(rct_peep *peep, int x, int y) int mechanic_is_location_in_patrol(rct_peep *mechanic, int x, int y) { // Check if location is in the park - if (!sub_664F72(x, y, mechanic->z)) + if (!map_is_location_owned(x, y, mechanic->z)) return 0; // Check if mechanic has patrol area @@ -320,4 +444,24 @@ int mechanic_is_location_in_patrol(rct_peep *mechanic, int x, int y) return 1; return staff_is_location_in_patrol_area(mechanic, x, y); +} + +/** + * + * rct2: 0x006C1955 + */ +void staff_reset_stats() +{ + uint16 spriteIndex; + rct_peep *peep; + + FOR_ALL_STAFF(spriteIndex, peep) { + peep->time_in_park = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); + peep->staff_lawns_mown = 0; + peep->staff_rides_fixed = 0; + peep->staff_gardens_watered = 0; + peep->staff_rides_inspected = 0; + peep->staff_litter_swept = 0; + peep->staff_bins_emptied = 0; + } } \ No newline at end of file diff --git a/src/peep/staff.h b/src/peep/staff.h index 758159489c..51467efecc 100644 --- a/src/peep/staff.h +++ b/src/peep/staff.h @@ -40,12 +40,25 @@ enum STAFF_TYPE { STAFF_TYPE_ENTERTAINER }; -void game_command_update_staff_colour(); -void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +enum STAFF_ORDERS{ + STAFF_ORDERS_SWEEPING = (1 << 0), + STAFF_ORDERS_WATER_FLOWERS = (1 << 1), + STAFF_ORDERS_EMPTY_BINS = (1 << 2), + STAFF_ORDERS_MOWING = (1 << 3), + STAFF_ORDERS_INSPECT_RIDES = (1 << 0), + STAFF_ORDERS_FIX_RIDES = (1 << 1) +}; -void update_staff_colour(uint8 staff_type, uint16 color); -uint16 hire_new_staff_member(uint8 staff_type); -void sub_6C0C3F(); +void game_command_update_staff_colour(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_hire_new_staff_member(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_staff_order(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_staff_patrol(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_fire_staff_member(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); + +void update_staff_colour(uint8 staffType, uint16 color); +uint16 hire_new_staff_member(uint8 staffType); +void staff_update_greyed_patrol_areas(); int mechanic_is_location_in_patrol(rct_peep *mechanic, int x, int y); +void staff_reset_stats(); #endif \ No newline at end of file diff --git a/src/platform/osinterface.c b/src/platform/osinterface.c deleted file mode 100644 index a7d6577071..0000000000 --- a/src/platform/osinterface.c +++ /dev/null @@ -1,924 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John, Alexander Overvoorde - * 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 -#include -#include -#include -#include - -#include "../addresses.h" -#include "../config.h" -#include "../cursors.h" -#include "../drawing/drawing.h" -#include "../input.h" -#include "../interface/keyboard_shortcut.h" -#include "../interface/screenshot.h" -#include "../interface/window.h" -#include "osinterface.h" - -typedef void(*update_palette_func)(char*, int, int); - -openrct2_cursor gCursorState; -const unsigned char *gKeysState; -unsigned char *gKeysPressed; -unsigned int gLastKeyPressed; -char* gTextInput; -int gTextInputLength; -int gTextInputMaxLength; -int gTextInputCursorPosition = 0; - -static void osinterface_create_window(); -static void osinterface_close_window(); -static void osinterface_resize(int width, int height); - -static SDL_Window *_window; -static SDL_Surface *_surface; -static SDL_Palette *_palette; - -static int _screenBufferSize; -static void *_screenBuffer; - -static SDL_Cursor* _cursors[NO_CURSORS]; - -static const int _fullscreen_modes[] = { 0, SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FULLSCREEN_DESKTOP }; - -static unsigned int _lastGestureTimestamp; -static float _gestureRadius; - -void osinterface_init() -{ - osinterface_create_window(); - - gKeysPressed = malloc(sizeof(unsigned char) * 256); - memset(gKeysPressed, 0, sizeof(unsigned char) * 256); - - // RCT2_CALLPROC(0x00404584); // dinput_init() -} - -int osinterface_scancode_to_rct_keycode(int sdl_key){ - char keycode = (char)SDL_GetKeyFromScancode((SDL_Scancode)sdl_key); - - // Until we reshufle the text files to use the new positions - // this will suffice to move the majority to the correct positions. - // Note any special buttons PgUp PgDwn are mapped wrong. - if (keycode >= 'a' && keycode <= 'z')keycode = toupper(keycode); - - return keycode; -} - -void osinterface_start_text_input(char* buffer, int max_length){ - SDL_StartTextInput(); - gTextInputMaxLength = max_length - 1; - gTextInput = buffer; - gTextInputCursorPosition = strnlen(gTextInput, max_length); - gTextInputLength = gTextInputCursorPosition; -} - -void osinterface_stop_text_input(){ - SDL_StopTextInput(); - gTextInput = NULL; -} - -/** - * This is not quite the same as the below function as we don't want to - * derfererence the cursor before the function. - * rct2: 0x0407956 - */ -void osinterface_set_cursor(char cursor){ - //HCURSOR hCurs = RCT2_ADDRESS(RCT2_ADDRESS_HCURSOR_START, HCURSOR)[cursor]; - //SetCursor((HCURSOR)hCurs); - SDL_SetCursor(_cursors[cursor]); -} -/** - *rct2: 0x0068352C - */ -static void osinterface_load_cursors(){ - - RCT2_GLOBAL(0x14241BC, uint32) = 2; - HINSTANCE hInst = RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_ARROW, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x74)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_BLANK, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0xA1)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_UP_ARROW, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x6D)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_UP_DOWN_ARROW, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x6E)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HAND_POINT, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x70)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_ZZZ, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x78)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_DIAGONAL_ARROWS, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x77)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_PICKER, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x7C)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_TREE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x83)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_FOUNTAIN_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x7F)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_STATUE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x80)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_BENCH_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x81)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_CROSS_HAIR, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x82)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_BIN_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x84)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_LAMPPOST_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x85)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_FENCE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8A)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_FLOWER_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x89)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_PATH_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8B)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_DIG_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8D)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_WATER_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8E)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HOUSE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8F)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_VOLCANO_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x90)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_WALK_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x91)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_PAINT_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x9E)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_ENTRANCE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x9F)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HAND_OPEN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0xA6)); - RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HAND_CLOSED, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0xA5)); - - _cursors[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); - _cursors[1] = SDL_CreateCursor(blank_cursor_data, blank_cursor_mask, 32, 32, BLANK_CURSOR_HOTX, BLANK_CURSOR_HOTY); - _cursors[2] = SDL_CreateCursor(up_arrow_cursor_data, up_arrow_cursor_mask, 32, 32, UP_ARROW_CURSOR_HOTX, UP_ARROW_CURSOR_HOTY); - _cursors[3] = SDL_CreateCursor(up_down_arrow_cursor_data, up_down_arrow_cursor_mask, 32, 32, UP_DOWN_ARROW_CURSOR_HOTX, UP_DOWN_ARROW_CURSOR_HOTY); - _cursors[4] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); - _cursors[5] = SDL_CreateCursor(zzz_cursor_data, zzz_cursor_mask, 32, 32, ZZZ_CURSOR_HOTX, ZZZ_CURSOR_HOTY); - _cursors[6] = SDL_CreateCursor(diagonal_arrow_cursor_data, diagonal_arrow_cursor_mask, 32, 32, DIAGONAL_ARROW_CURSOR_HOTX, DIAGONAL_ARROW_CURSOR_HOTY); - _cursors[7] = SDL_CreateCursor(picker_cursor_data, picker_cursor_mask, 32, 32, PICKER_CURSOR_HOTX, PICKER_CURSOR_HOTY); - _cursors[8] = SDL_CreateCursor(tree_down_cursor_data, tree_down_cursor_mask, 32, 32, TREE_DOWN_CURSOR_HOTX, TREE_DOWN_CURSOR_HOTY); - _cursors[9] = SDL_CreateCursor(fountain_down_cursor_data, fountain_down_cursor_mask, 32, 32, FOUNTAIN_DOWN_CURSOR_HOTX, FOUNTAIN_DOWN_CURSOR_HOTY); - _cursors[10] = SDL_CreateCursor(statue_down_cursor_data, statue_down_cursor_mask, 32, 32, STATUE_DOWN_CURSOR_HOTX, STATUE_DOWN_CURSOR_HOTY); - _cursors[11] = SDL_CreateCursor(bench_down_cursor_data, bench_down_cursor_mask, 32, 32, BENCH_DOWN_CURSOR_HOTX, BENCH_DOWN_CURSOR_HOTY); - _cursors[12] = SDL_CreateCursor(cross_hair_cursor_data, cross_hair_cursor_mask, 32, 32, CROSS_HAIR_CURSOR_HOTX, CROSS_HAIR_CURSOR_HOTY); - _cursors[13] = SDL_CreateCursor(bin_down_cursor_data, bin_down_cursor_mask, 32, 32, BIN_DOWN_CURSOR_HOTX, BIN_DOWN_CURSOR_HOTY); - _cursors[14] = SDL_CreateCursor(lamppost_down_cursor_data, lamppost_down_cursor_mask, 32, 32, LAMPPOST_DOWN_CURSOR_HOTX, LAMPPOST_DOWN_CURSOR_HOTY); - _cursors[15] = SDL_CreateCursor(fence_down_cursor_data, fence_down_cursor_mask, 32, 32, FENCE_DOWN_CURSOR_HOTX, FENCE_DOWN_CURSOR_HOTY); - _cursors[16] = SDL_CreateCursor(flower_down_cursor_data, flower_down_cursor_mask, 32, 32, FLOWER_DOWN_CURSOR_HOTX, FLOWER_DOWN_CURSOR_HOTY); - _cursors[17] = SDL_CreateCursor(path_down_cursor_data, path_down_cursor_mask, 32, 32, PATH_DOWN_CURSOR_HOTX, PATH_DOWN_CURSOR_HOTY); - _cursors[18] = SDL_CreateCursor(dig_down_cursor_data, dig_down_cursor_mask, 32, 32, DIG_DOWN_CURSOR_HOTX, DIG_DOWN_CURSOR_HOTY); - _cursors[19] = SDL_CreateCursor(water_down_cursor_data, water_down_cursor_mask, 32, 32, WATER_DOWN_CURSOR_HOTX, WATER_DOWN_CURSOR_HOTY); - _cursors[20] = SDL_CreateCursor(house_down_cursor_data, house_down_cursor_mask, 32, 32, HOUSE_DOWN_CURSOR_HOTX, HOUSE_DOWN_CURSOR_HOTY); - _cursors[21] = SDL_CreateCursor(volcano_down_cursor_data, volcano_down_cursor_mask, 32, 32, VOLCANO_DOWN_CURSOR_HOTX, VOLCANO_DOWN_CURSOR_HOTY); - _cursors[22] = SDL_CreateCursor(walk_down_cursor_data, walk_down_cursor_mask, 32, 32, WALK_DOWN_CURSOR_HOTX, WALK_DOWN_CURSOR_HOTY); - _cursors[23] = SDL_CreateCursor(paint_down_cursor_data, paint_down_cursor_mask, 32, 32, PAINT_DOWN_CURSOR_HOTX, PAINT_DOWN_CURSOR_HOTY); - _cursors[24] = SDL_CreateCursor(entrance_down_cursor_data, entrance_down_cursor_mask, 32, 32, ENTRANCE_DOWN_CURSOR_HOTX, ENTRANCE_DOWN_CURSOR_HOTY); - _cursors[25] = SDL_CreateCursor(hand_open_cursor_data, hand_open_cursor_mask, 32, 32, HAND_OPEN_CURSOR_HOTX, HAND_OPEN_CURSOR_HOTY); - _cursors[26] = SDL_CreateCursor(hand_closed_cursor_data, hand_closed_cursor_mask, 32, 32, HAND_CLOSED_CURSOR_HOTX, HAND_CLOSED_CURSOR_HOTY); - osinterface_set_cursor(CURSOR_ARROW); - RCT2_GLOBAL(0x14241BC, uint32) = 0; -} - -static void osinterface_unload_cursors(){ - for (int i = 0; i < NO_CURSORS; ++i){ - if (_cursors[i] != NULL)SDL_FreeCursor(_cursors[i]); - } -} - -static void osinterface_create_window() -{ - SDL_SysWMinfo wmInfo; - HWND hWnd; - int width, height; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - RCT2_ERROR("SDL_Init %s", SDL_GetError()); - exit(-1); - } - - // stuff - { - osinterface_load_cursors(); - RCT2_CALLPROC_EBPSAFE(0x0068371D); - - width = gGeneral_config.window_width; - height = gGeneral_config.window_height; - - if (width == -1) width = 640; - if (height == -1) height = 480; - } - - RCT2_GLOBAL(0x009E2D8C, sint32) = 0; - - _window = SDL_CreateWindow("OpenRCT2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, - _fullscreen_modes[gGeneral_config.fullscreen_mode] | SDL_WINDOW_RESIZABLE); - if (!_window) { - RCT2_ERROR("SDL_CreateWindow failed %s", SDL_GetError()); - exit(-1); - } - - SDL_VERSION(&wmInfo.version); - // Get the HWND context - if (SDL_GetWindowWMInfo(_window, &wmInfo) != SDL_TRUE) { - RCT2_ERROR("SDL_GetWindowWMInfo failed %s", SDL_GetError()); - exit(-1); - } - hWnd = wmInfo.info.win.window; - RCT2_GLOBAL(0x009E2D70, HWND) = hWnd; - - // Set the update palette function pointer - RCT2_GLOBAL(0x009E2BE4, update_palette_func) = osinterface_update_palette; - - // Initialise the surface, palette and draw buffer - osinterface_resize(width, height); -} - - -static void osinterface_resize(int width, int height) -{ - rct_drawpixelinfo *screenDPI; - int newScreenBufferSize; - void *newScreenBuffer; - - if (_surface != NULL) - SDL_FreeSurface(_surface); - if (_palette != NULL) - SDL_FreePalette(_palette); - - _surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0); - _palette = SDL_AllocPalette(256); - - if (!_surface || !_palette) { - RCT2_ERROR("%p || %p == NULL %s", _surface, _palette, SDL_GetError()); - exit(-1); - } - - if (SDL_SetSurfacePalette(_surface, _palette)) { - RCT2_ERROR("SDL_SetSurfacePalette failed %s", SDL_GetError()); - exit(-1); - } - - newScreenBufferSize = _surface->pitch * _surface->h; - newScreenBuffer = malloc(newScreenBufferSize); - if (_screenBuffer == NULL) { - memset(newScreenBuffer, 0, newScreenBufferSize); - } else { - memcpy(newScreenBuffer, _screenBuffer, min(_screenBufferSize, newScreenBufferSize)); - if (newScreenBufferSize - _screenBufferSize > 0) - memset((uint8*)newScreenBuffer + _screenBufferSize, 0, newScreenBufferSize - _screenBufferSize); - free(_screenBuffer); - } - - _screenBuffer = newScreenBuffer; - _screenBufferSize = newScreenBufferSize; - - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) = width; - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) = height; - - screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); - screenDPI->bits = _screenBuffer; - screenDPI->x = 0; - screenDPI->y = 0; - screenDPI->width = width; - screenDPI->height = height; - screenDPI->pitch = _surface->pitch - _surface->w; - - RCT2_GLOBAL(0x009ABDF0, uint8) = 6; - RCT2_GLOBAL(0x009ABDF1, uint8) = 3; - RCT2_GLOBAL(0x009ABDF2, uint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16) = 64; - RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16) = 8; - RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) = (width >> 6) + 1; - RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32) = (height >> 3) + 1; - - window_resize_gui(width, height); - //RCT2_CALLPROC_EBPSAFE(0x0066B905); // resize_gui() - - gfx_invalidate_screen(); -} - -void osinterface_update_palette(char* colours, int start_index, int num_colours) -{ - SDL_Color base[256]; - SDL_Surface *surface; - int i; - - surface = SDL_GetWindowSurface(_window); - if (!surface) { - RCT2_ERROR("SDL_GetWindowSurface failed %s", SDL_GetError()); - exit(1); - } - - for (i = 0; i < 256; i++) { - base[i].r = colours[2]; - base[i].g = colours[1]; - base[i].b = colours[0]; - base[i].a = 0; - colours += 4; - } - - if (SDL_SetPaletteColors(_palette, base, 0, 256)) { - RCT2_ERROR("SDL_SetPaletteColors failed %s", SDL_GetError()); - exit(1); - } -} - -void osinterface_draw() -{ - // Lock the surface before setting its pixels - if (SDL_MUSTLOCK(_surface)) - if (SDL_LockSurface(_surface) < 0) { - RCT2_ERROR("locking failed %s", SDL_GetError()); - return; - } - - // Copy pixels from the virtual screen buffer to the surface - memcpy(_surface->pixels, _screenBuffer, _surface->pitch * _surface->h); - - // Unlock the surface - if (SDL_MUSTLOCK(_surface)) - SDL_UnlockSurface(_surface); - - // Copy the surface to the window - if (SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(_window), NULL)) { - RCT2_ERROR("SDL_BlitSurface %s", SDL_GetError()); - exit(1); - } - if (SDL_UpdateWindowSurface(_window)) { - RCT2_ERROR("SDL_UpdateWindowSurface %s", SDL_GetError()); - exit(1); - } -} - -void osinterface_process_messages() -{ - SDL_Event e; - - gLastKeyPressed = 0; - // gCursorState.wheel = 0; - gCursorState.left &= ~CURSOR_CHANGED; - gCursorState.middle &= ~CURSOR_CHANGED; - gCursorState.right &= ~CURSOR_CHANGED; - gCursorState.old = 0; - - while (SDL_PollEvent(&e)) { - switch (e.type) { - case SDL_QUIT: -// rct2_finish(); - rct2_quit(); - break; - case SDL_WINDOWEVENT: - if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) - osinterface_resize(e.window.data1, e.window.data2); - break; - case SDL_MOUSEMOTION: - RCT2_GLOBAL(0x0142406C, int) = e.motion.x; - RCT2_GLOBAL(0x01424070, int) = e.motion.y; - - gCursorState.x = e.motion.x; - gCursorState.y = e.motion.y; - break; - case SDL_MOUSEWHEEL: - gCursorState.wheel += e.wheel.y * 128; - break; - case SDL_MOUSEBUTTONDOWN: - RCT2_GLOBAL(0x01424318, int) = e.button.x; - RCT2_GLOBAL(0x0142431C, int) = e.button.y; - switch (e.button.button) { - case SDL_BUTTON_LEFT: - store_mouse_input(1); - gCursorState.left = CURSOR_PRESSED; - gCursorState.old = 1; - break; - case SDL_BUTTON_MIDDLE: - gCursorState.middle = CURSOR_PRESSED; - break; - case SDL_BUTTON_RIGHT: - store_mouse_input(3); - gCursorState.right = CURSOR_PRESSED; - gCursorState.old = 2; - break; - } - break; - case SDL_MOUSEBUTTONUP: - RCT2_GLOBAL(0x01424318, int) = e.button.x; - RCT2_GLOBAL(0x0142431C, int) = e.button.y; - switch (e.button.button) { - case SDL_BUTTON_LEFT: - store_mouse_input(2); - gCursorState.left = CURSOR_RELEASED; - gCursorState.old = 3; - break; - case SDL_BUTTON_MIDDLE: - gCursorState.middle = CURSOR_RELEASED; - break; - case SDL_BUTTON_RIGHT: - store_mouse_input(4); - gCursorState.right = CURSOR_RELEASED; - gCursorState.old = 4; - break; - } - break; - case SDL_KEYDOWN: - gLastKeyPressed = e.key.keysym.sym; - gKeysPressed[e.key.keysym.scancode] = 1; - if (e.key.keysym.sym == SDLK_RETURN && e.key.keysym.mod & KMOD_ALT) - osinterface_set_fullscreen_mode(!gGeneral_config.fullscreen_mode); - - // Text input - - // If backspace and we have input text with a cursor position none zero - if (e.key.keysym.sym == SDLK_BACKSPACE && gTextInputLength > 0 && gTextInput && gTextInputCursorPosition){ - // When at max length don't shift the data left - // as it would buffer overflow. - if (gTextInputCursorPosition != gTextInputMaxLength) - memmove(gTextInput + gTextInputCursorPosition - 1, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - 1); - gTextInput[gTextInputLength - 1] = '\0'; - gTextInputCursorPosition--; - gTextInputLength--; - } - if (e.key.keysym.sym == SDLK_END){ - gTextInputCursorPosition = gTextInputLength; - } - if (e.key.keysym.sym == SDLK_HOME){ - gTextInputCursorPosition = 0; - } - if (e.key.keysym.sym == SDLK_DELETE && gTextInputLength > 0 && gTextInput && gTextInputCursorPosition != gTextInputLength){ - memmove(gTextInput + gTextInputCursorPosition, gTextInput + gTextInputCursorPosition + 1, gTextInputMaxLength - gTextInputCursorPosition - 1); - gTextInput[gTextInputMaxLength - 1] = '\0'; - gTextInputLength--; - } - if (e.key.keysym.sym == SDLK_LEFT && gTextInput){ - if (gTextInputCursorPosition) gTextInputCursorPosition--; - } - else if (e.key.keysym.sym == SDLK_RIGHT && gTextInput){ - if (gTextInputCursorPosition < gTextInputLength) gTextInputCursorPosition++; - } - break; - case SDL_MULTIGESTURE: - if (e.mgesture.numFingers == 2) { - if (e.mgesture.timestamp > _lastGestureTimestamp + 1000) - _gestureRadius = 0; - _lastGestureTimestamp = e.mgesture.timestamp; - _gestureRadius += e.mgesture.dDist; - - // Zoom gesture - const int tolerance = 128; - int gesturePixels = (int)(_gestureRadius * RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); - if (gesturePixels > tolerance) { - _gestureRadius = 0; - keyboard_shortcut_handle_command(SHORTCUT_ZOOM_VIEW_IN); - } else if (gesturePixels < -tolerance) { - _gestureRadius = 0; - keyboard_shortcut_handle_command(SHORTCUT_ZOOM_VIEW_OUT); - } - } - break; - - case SDL_TEXTINPUT: - if (gTextInputLength < gTextInputMaxLength && gTextInput){ - // Convert the utf-8 code into rct ascii - char new_char; - if (!(e.text.text[0] & 0x80)) - new_char = *e.text.text; - else if (!(e.text.text[0] & 0x20)) - new_char = ((e.text.text[0] & 0x1F) << 6) | (e.text.text[1] & 0x3F); - - // If inserting in center of string make space for new letter - if (gTextInputLength > gTextInputCursorPosition){ - memmove(gTextInput + gTextInputCursorPosition + 1, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - 1); - gTextInput[gTextInputCursorPosition] = new_char; - gTextInputLength++; - } - else gTextInput[gTextInputLength++] = new_char; - - gTextInputCursorPosition++; - } - break; - default: - break; - } - } - - gCursorState.any = gCursorState.left | gCursorState.middle | gCursorState.right; - - // Updates the state of the keys - int numKeys = 256; - gKeysState = SDL_GetKeyboardState(&numKeys); -} - -static void osinterface_close_window() -{ - if (_window != NULL) - SDL_DestroyWindow(_window); - if (_surface != NULL) - SDL_FreeSurface(_surface); - if (_palette != NULL) - SDL_FreePalette(_palette); - osinterface_unload_cursors(); -} - -void osinterface_free() -{ - free(gKeysPressed); - - osinterface_close_window(); - SDL_Quit(); -} - -void osinterface_set_fullscreen_mode(int mode){ - if (mode == gGeneral_config.fullscreen_mode) - return; - - if (SDL_SetWindowFullscreen(_window, _fullscreen_modes[mode])){ - RCT2_ERROR("SDL_SetWindowFullscreen %s", SDL_GetError()); - exit(1); - } - //SDL automatically resizes the fullscreen window to the nearest allowed screen resolution - //No need to call osinterface_resize() here, SDL_WINDOWEVENT_SIZE_CHANGED event will be triggered anyway - - gGeneral_config.fullscreen_mode = mode; - - config_save(); -} - -/** - * - * rct2: 0x00407978 - */ -int osinterface_407978(rct2_install_info* install_info, char* source, char* font, uint8 charset) -{ - char subkey[MAX_PATH]; - char subkey2[MAX_PATH]; - strcpy(subkey, "Software\\Infogrames\\"); - strcat(subkey, source); - strcpy(subkey2, "Software\\Fish Technology Group\\"); - strcat(subkey2, source); - LOGFONTA lf; - memset(&lf, 0, sizeof(lf)); - lf.lfCharSet = charset; - lf.lfHeight = 12; - lf.lfWeight = 400; - strcpy(lf.lfFaceName, font); - RCT2_GLOBAL(RCT2_ADDRESS_HFONT, HFONT) = CreateFontIndirectA(&lf); - HKEY hkey; - if (RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey, &hkey) != ERROR_SUCCESS && RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey2, &hkey) != ERROR_SUCCESS) { - return 0; - } else { - DWORD type; - DWORD size = 260; - RegQueryValueExA(hkey, "Title", 0, &type, install_info->title, &size); - size = 260; - RegQueryValueExA(hkey, "Path", 0, &type, install_info->path, &size); - install_info->var_20C = 235960; - size = 4; - RegQueryValueExA(hkey, "InstallLevel", 0, &type, (LPBYTE)&install_info->installlevel, &size); - for (int i = 0; i <= 15; i++) { - char name[100]; - sprintf(name, "AddonPack%d", i); - size = sizeof(install_info->addon[i]); - if (RegQueryValueExA(hkey, name, 0, &type, install_info->addon[i], &size) == ERROR_SUCCESS) { - install_info->addons |= (1 << i); - } - } - RegCloseKey(hkey); - return 1; - } -} - -/** - * - * rct2: 0x00407D80 - */ -int osinterface_get_cursor_pos(int* x, int* y) -{ - POINT point; - GetCursorPos(&point); - *x = point.x; - *y = point.y; -} - -/** - * - * rct2: 0x00407E15 - */ -int osinterface_print_window_message(UINT msg, WPARAM wparam, LPARAM lparam) -{ - const char* msgname = "NULL"; - // get the string representation of the msg id, from 190 different values in 0x009A61D8 - 0x009A8873 - // not going to bother reading those since this function is going to be unused and taken out anyways - char temp[1024]; - sprintf(temp, "Message id = %s (%i), wParam = 0x%x, lParam = 0x%x\n", msgname, msg, wparam, lparam); - OutputDebugStringA(temp); - return 1; -} - -/** - * - * rct2: 0x00407E6E - */ -int osinterface_progressbar_create(char* title, int a2) -{ - DWORD style = WS_VISIBLE | WS_BORDER | WS_DLGFRAME; - if (a2) { - style = WS_VISIBLE | WS_BORDER | WS_DLGFRAME | PBS_SMOOTH; - } - int width = 340; - int height = GetSystemMetrics(SM_CYCAPTION) + 24; - HWND hwnd = CreateWindowExA(WS_EX_TOPMOST | WS_EX_DLGMODALFRAME, "msctls_progress32", title, style, (RCT2_GLOBAL(0x01423C08, sint32) - width) / 2, (RCT2_GLOBAL(0x01423C0C, sint32) - height) / 2, width, height, 0, 0, RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE), 0); - RCT2_GLOBAL(RCT2_ADDRESS_PROGRESSBAR_HWND, HWND) = hwnd; - if (hwnd) { - RCT2_GLOBAL(0x009E2DFC, uint32) = 1; - if (RCT2_GLOBAL(RCT2_ADDRESS_HFONT, HFONT)) { - SendMessageA(hwnd, WM_SETFONT, (WPARAM)RCT2_GLOBAL(RCT2_ADDRESS_HFONT, HFONT), 1); - } - SetWindowTextA(hwnd, title); - osinterface_progressbar_setmax(0xFF); - osinterface_progressbar_setpos(0); - return 1; - } else { - return 0; - } -} - -/** - * - * rct2: 0x00407F16 - */ -int osinterface_progressbar_destroy() -{ - if (DestroyWindow(RCT2_GLOBAL(RCT2_ADDRESS_PROGRESSBAR_HWND, HWND))) { - RCT2_GLOBAL(0x009E2DFC, uint32) = 0; - return 1; - } else { - return 0; - } -} - -/** - * - * rct2: 0x00407F2E - */ -void osinterface_progressbar_setmax(int max) -{ - SendMessageA(RCT2_GLOBAL(RCT2_ADDRESS_PROGRESSBAR_HWND, HWND), PBM_SETRANGE, MAKEWPARAM(0, max), 0); - SendMessageA(RCT2_GLOBAL(RCT2_ADDRESS_PROGRESSBAR_HWND, HWND), PBM_SETSTEP, 1, 0); -} - -/** - * - * rct2: 0x00407F60 - */ -void osinterface_progressbar_setpos(int pos) -{ - SendMessageA(RCT2_GLOBAL(RCT2_ADDRESS_PROGRESSBAR_HWND, HWND), PBM_SETPOS, MAKEWPARAM(pos, 0), 0); -} - -/** - * - * rct2: 0x00407F78 - */ -int osinterface_file_seek_from_begin(HANDLE handle, int offset) -{ - return SetFilePointer(handle, offset, 0, FILE_BEGIN); -} - -/** - * - * rct2: 0x00407F8B - */ -int osinterface_file_seek_from_current(HANDLE handle, int offset) -{ - return SetFilePointer(handle, offset, 0, FILE_CURRENT); -} - -/** - * - * rct2: 0x00407F9E - */ -int osinterface_file_seek_from_end(HANDLE handle, int offset) -{ - return SetFilePointer(handle, offset, 0, FILE_END); -} - -/** - * - * rct2: 0x00407FB1 - */ -int osinterface_file_read(HANDLE handle, void* data, int size) -{ - DWORD read; - BOOL result; - if (size == -1) { - DWORD current = SetFilePointer(handle, 0, 0, FILE_CURRENT); - DWORD remaining = SetFilePointer(handle, 0, 0, FILE_END) - current; - result = ReadFile(handle, data, remaining, &read, 0); - } else { - result = ReadFile(handle, data, size, &read, 0); - } - if (result) { - return read; - } else { - return -1; - } -} - -/** - * - * rct2: 0x00408024 - */ -int osinterface_file_write(HANDLE handle, const void* data, int size) -{ - DWORD written; - if (WriteFile(handle, data, size, &written, 0)) { - return written; - } else { - return -1; - } -} - -/** - * - * rct2: 0x0040804A - */ -int osinterface_file_close(HANDLE handle) -{ - if (handle) { - return CloseHandle(handle); - } else { - return 1; - } -} - -/** - * - * rct2: 0x00408060 - */ -HANDLE osinterface_file_open(const char* filename) -{ - return CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, 0); -} - -/** - * - * rct2: 0x0040807D - */ -HANDLE osinterface_file_create(const char* filename) -{ - return CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); -} - -/** - * - * rct2: 0x00408099 - */ -int osinterface_file_move(const char* srcfilename, const char* dstfilename) -{ - return (MoveFileA(srcfilename, dstfilename) != 0) - 1; -} - -/** - * - * rct2: 0x004080AF - */ -int osinterface_file_delete(const char* filename) -{ - return (DeleteFileA(filename) != 0) - 1; -} - -/** - * - * rct2: 0x004080EA - */ -int osinterface_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName) -{ - char initialDirectory[MAX_PATH], *dotAddress, *slashAddress; - OPENFILENAME openFileName; - BOOL result; - int tmp; - DWORD commonFlags; - - // Get directory path from given filename - strcpy(initialDirectory, filename); - dotAddress = strrchr(initialDirectory, '.'); - if (dotAddress != NULL) { - slashAddress = strrchr(initialDirectory, '\\'); - if (slashAddress < dotAddress) - *(slashAddress + 1) = 0; - } - - // Clear filename - if (type != 0) - *filename = 0; - - // Set open file name options - memset(&openFileName, 0, sizeof(OPENFILENAME)); - openFileName.lStructSize = sizeof(OPENFILENAME); - openFileName.hwndOwner = RCT2_GLOBAL(0x009E2D70, HWND); - openFileName.lpstrFile = filename; - openFileName.nMaxFile = MAX_PATH; - openFileName.lpstrInitialDir = initialDirectory; - openFileName.lpstrTitle = title; - - // Copy filter name - strcpy((char*)0x01423800, filterName); - - // Copy filter pattern - strcpy((char*)0x01423800 + strlen(filterName) + 1, filterPattern); - *((char*)(0x01423800 + strlen(filterName) + 1 + strlen(filterPattern) + 1)) = 0; - openFileName.lpstrFilter = (char*)0x01423800; - - // - tmp = RCT2_GLOBAL(0x009E2C74, uint32); - if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1) - RCT2_GLOBAL(0x009E2C74, uint32) = 1; - - // Open dialog - commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; - if (type == 0) { - openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT; - result = GetSaveFileName(&openFileName); - } else if (type == 1) { - openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST; - result = GetOpenFileName(&openFileName); - } - - // - RCT2_GLOBAL(0x009E2C74, uint32) = tmp; - - return result; -} - -void osinterface_show_messagebox(char* message) -{ - MessageBox(NULL, message, "OpenRCT2", MB_OK); -} - -char* osinterface_open_directory_browser(char *title) -{ - BROWSEINFO bi; - char pszBuffer[MAX_PATH]; - LPITEMIDLIST pidl; - LPMALLOC lpMalloc; - - // Initialize COM - if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED))) { - CoUninitialize(); - - log_error("Error opening directory browse window"); - return 0; - } - - // Get a pointer to the shell memory allocator - if (FAILED(SHGetMalloc(&lpMalloc))) { - CoUninitialize(); - - log_error("Error opening directory browse window"); - return 0; - } - - bi.hwndOwner = NULL; - bi.pidlRoot = NULL; - bi.pszDisplayName = pszBuffer; - bi.lpszTitle = _T(title); - bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS; - bi.lpfn = NULL; - bi.lParam = 0; - - char *outPath = NULL; - - if (pidl = SHBrowseForFolder(&bi)) { - // Copy the path directory to the buffer - if (SHGetPathFromIDList(pidl, pszBuffer)) { - // Store pszBuffer (and the path) in the outPath - outPath = (char*) malloc(strlen(pszBuffer)+1); - strcpy(outPath, pszBuffer); - } - } - CoUninitialize(); - return outPath; -} - -char* osinterface_get_orct2_homefolder() -{ - char *path=NULL; - path = malloc(sizeof(char) * MAX_PATH); - if (path == NULL){ - log_fatal("Error allocating memory!"); - exit(EXIT_FAILURE); - } - - path[0] = '\0'; - - if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path))) - strcat(path, "\\OpenRCT2"); - - return path; -} - -char *osinterface_get_orct2_homesubfolder(const char *subFolder) -{ - char *path = osinterface_get_orct2_homefolder(); - strcat(path, "\\"); - strcat(path, subFolder); - return path; -} - -char osinterface_get_path_separator() -{ - return '\\'; -} diff --git a/src/platform/osinterface.h b/src/platform/osinterface.h deleted file mode 100644 index 27561cd889..0000000000 --- a/src/platform/osinterface.h +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * 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 _SDL_INTERFACE_H_ -#define _SDL_INTERFACE_H_ - -#include -#include "../common.h" - -enum { - CURSOR_UP = 0, - CURSOR_DOWN = 1, - CURSOR_CHANGED = 2, - CURSOR_RELEASED = CURSOR_UP | CURSOR_CHANGED, - CURSOR_PRESSED = CURSOR_DOWN | CURSOR_CHANGED, -}; - -enum{ - CURSOR_ARROW = 0, - CURSOR_BLANK = 1, - CURSOR_UP_ARROW = 2, - CURSOR_UP_DOWN_ARROW = 3, - CURSOR_HAND_POINT = 4, - CURSOR_ZZZ = 5, - CURSOR_DIAGONAL_ARROWS = 6, - CURSOR_PICKER = 7, - CURSOR_TREE_DOWN = 8, - CURSOR_FOUNTAIN_DOWN = 9, - CURSOR_STATUE_DOWN = 10, - CURSOR_BENCH_DOWN = 11, - CURSOR_CROSS_HAIR = 12, - CURSOR_BIN_DOWN = 13, - CURSOR_LAMPPOST_DOWN = 14, - CURSOR_FENCE_DOWN = 15, - CURSOR_FLOWER_DOWN = 16, - CURSOR_PATH_DOWN = 17, - CURSOR_DIG_DOWN = 18, - CURSOR_WATER_DOWN = 19, - CURSOR_HOUSE_DOWN = 20, - CURSOR_VOLCANO_DOWN = 21, - CURSOR_WALK_DOWN = 22, - CURSOR_PAINT_DOWN = 23, - CURSOR_ENTRANCE_DOWN = 24, - CURSOR_HAND_OPEN = 25, - CURSOR_HAND_CLOSED = 26 -}; - -typedef struct { - int x, y; - unsigned char left, middle, right, any; - int wheel; - int old; -} openrct2_cursor; - -typedef struct { - uint32 installlevel; - char title[260]; - char path[260]; - uint32 var_20C; - uint8 pad_210[0x100]; - char addon[16][0x80]; - uint32 addons; //0xB10 -} rct2_install_info; - -extern openrct2_cursor gCursorState; -extern const unsigned char *gKeysState; -extern unsigned char *gKeysPressed; -extern unsigned int gLastKeyPressed; -extern int gTextInputCursorPosition; - -void osinterface_start_text_input(char* buffer, int max_length); -void osinterface_stop_text_input(); -void osinterface_init(); -void osinterface_process_messages(); -void osinterface_draw(); -void osinterface_free(); -void osinterface_update_palette(char* colours, int start_index, int num_colours); - -void osinterface_set_fullscreen_mode(int mode); - -void osinterface_progressbar_setmax(int max); -void osinterface_progressbar_setpos(int pos); - -void osinterface_set_cursor(char cursor); - -HANDLE osinterface_file_open(const char* filename); -int osinterface_file_read(HANDLE handle, void* data, int size); -int osinterface_file_close(HANDLE handle); - -int osinterface_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName); -void osinterface_show_messagebox(char* message); -char* osinterface_open_directory_browser(char *title); - -char* osinterface_get_orct2_homefolder(); -char *osinterface_get_orct2_homesubfolder(const char *subFolder); - -char osinterface_get_path_separator(); -int osinterface_scancode_to_rct_keycode(int sdl_key); - -#endif diff --git a/src/platform/platform.h b/src/platform/platform.h index 2b2e8db336..ee3a146cd1 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -21,6 +21,8 @@ #ifndef _PLATFORM_H_ #define _PLATFORM_H_ +#include + #include "../common.h" #ifndef MAX_PATH @@ -29,12 +31,58 @@ #define INVALID_HANDLE -1 +typedef struct { + int width, height; +} resolution; + typedef struct { const char *path; uint64 size; uint64 last_modified; } file_info; +typedef struct { + int x, y; + unsigned char left, middle, right, any; + int wheel; + int old; +} openrct2_cursor; + +enum { + CURSOR_UP = 0, + CURSOR_DOWN = 1, + CURSOR_CHANGED = 2, + CURSOR_RELEASED = CURSOR_UP | CURSOR_CHANGED, + CURSOR_PRESSED = CURSOR_DOWN | CURSOR_CHANGED, +}; + +extern openrct2_cursor gCursorState; +extern const unsigned char *gKeysState; +extern unsigned char *gKeysPressed; +extern unsigned int gLastKeyPressed; +extern int gTextInputCursorPosition; +extern int gTextInputLength; + +extern int gResolutionsAllowAnyAspectRatio; +extern int gNumResolutions; +extern resolution *gResolutions; +extern SDL_Window *gWindow; + +// Platform shared definitions +void platform_update_fullscreen_resolutions(); +void platform_get_closest_resolution(int inWidth, int inHeight, int *outWidth, int *outHeight); +void platform_init(); +void platform_draw(); +void platform_free(); +void platform_update_palette(char* colours, int start_index, int num_colours); +void platform_set_fullscreen_mode(int mode); +void platform_set_cursor(char cursor); +void platform_refresh_video(); +void platform_process_messages(); +int platform_scancode_to_rct_keycode(int sdl_key); +void platform_start_text_input(char* buffer, int max_length); +void platform_stop_text_input(); + // Platform specific definitions char platform_get_path_separator(); int platform_file_exists(const char *path); @@ -44,10 +92,36 @@ int platform_lock_single_instance(); int platform_enumerate_files_begin(const char *pattern); int platform_enumerate_files_next(int handle, file_info *outFileInfo); void platform_enumerate_files_end(int handle); +int platform_enumerate_directories_begin(const char *directory); +int platform_enumerate_directories_next(int handle, char *path); +void platform_enumerate_directories_end(int handle); +int platform_file_copy(const char *srcPath, const char *dstPath); +int platform_file_move(const char *srcPath, const char *dstPath); +int platform_file_delete(const char *path); void platform_hide_cursor(); void platform_show_cursor(); void platform_get_cursor_position(int *x, int *y); void platform_set_cursor_position(int x, int y); unsigned int platform_get_ticks(); +void platform_get_user_directory(char *outPath, const char *subDirectory); +void platform_show_messagebox(char *message); +int platform_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName); +char *platform_open_directory_browser(char *title); +uint8 platform_get_locale_currency(); +uint16 platform_get_locale_language(); +uint8 platform_get_locale_measurement_format(); +uint8 platform_get_locale_temperature_format(); + +// Windows specific definitions +#ifdef _WIN32 + // Defining WIN32_LEAN_AND_MEAN breaks dsound.h in audio.h (uncomment when dsound is finally removed) + // #ifndef WIN32_LEAN_AND_MEAN + // #define WIN32_LEAN_AND_MEAN + // #endif + #include + + int windows_get_registry_install_info(rct2_install_info *installInfo, char *source, char *font, uint8 charset); + HWND windows_get_window_handle(); +#endif #endif \ No newline at end of file diff --git a/src/platform/shared.c b/src/platform/shared.c index 20a00a3bd2..6e2ea0cf26 100644 --- a/src/platform/shared.c +++ b/src/platform/shared.c @@ -18,3 +18,816 @@ * along with this program. If not, see . *****************************************************************************/ +#include +#include +#include "../addresses.h" +#include "../config.h" +#include "../cursors.h" +#include "../drawing/drawing.h" +#include "../interface/console.h" +#include "../interface/keyboard_shortcut.h" +#include "../interface/window.h" +#include "../input.h" +#include "../openrct2.h" +#include "platform.h" + +typedef void(*update_palette_func)(char*, int, int); + +openrct2_cursor gCursorState; +const unsigned char *gKeysState; +unsigned char *gKeysPressed; +unsigned int gLastKeyPressed; +char* gTextInput; +int gTextInputLength; +int gTextInputMaxLength; +int gTextInputCursorPosition = 0; + +int gNumResolutions = 0; +resolution *gResolutions = NULL; +int gResolutionsAllowAnyAspectRatio = 0; + +SDL_Window *gWindow = NULL; +SDL_Renderer *gRenderer = NULL; +SDL_Texture *gBufferTexture = NULL; +SDL_PixelFormat *gBufferTextureFormat = NULL; +SDL_Color gPalette[256]; +uint32 gPaletteHWMapped[256]; + +static SDL_Surface *_surface; +static SDL_Palette *_palette; + +static void *_screenBuffer; +static int _screenBufferSize; +static int _screenBufferWidth; +static int _screenBufferHeight; +static int _screenBufferPitch; + +static SDL_Cursor* _cursors[CURSOR_COUNT]; +static const int _fullscreen_modes[] = { 0, SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FULLSCREEN_DESKTOP }; +static unsigned int _lastGestureTimestamp; +static float _gestureRadius; + +static void platform_create_window(); +static void platform_load_cursors(); +static void platform_unload_cursors(); + +static void platform_refresh_screenbuffer(int width, int height, int pitch); + +int resolution_sort_func(const void *pa, const void *pb) +{ + const resolution *a = (resolution*)pa; + const resolution *b = (resolution*)pb; + + int areaA = a->width * a->height; + int areaB = b->width * b->height; + + if (areaA == areaB) return 0; + if (areaA < areaB) return -1; + return 1; +} + +void platform_update_fullscreen_resolutions() +{ + int i, displayIndex, numDisplayModes; + SDL_DisplayMode mode; + resolution *resLook, *resPlace; + float desktopAspectRatio, aspectRatio; + + // Query number of display modes + displayIndex = SDL_GetWindowDisplayIndex(gWindow); + numDisplayModes = SDL_GetNumDisplayModes(displayIndex); + + // Get desktop aspect ratio + SDL_GetDesktopDisplayMode(displayIndex, &mode); + desktopAspectRatio = (float)mode.w / mode.h; + + if (gResolutions != NULL) + free(gResolutions); + + // Get resolutions + gNumResolutions = numDisplayModes; + gResolutions = malloc(gNumResolutions * sizeof(resolution)); + + gNumResolutions = 0; + for (i = 0; i < numDisplayModes; i++) { + SDL_GetDisplayMode(displayIndex, i, &mode); + + aspectRatio = (float)mode.w / mode.h; + if (gResolutionsAllowAnyAspectRatio || fabs(desktopAspectRatio - aspectRatio) < 0.0001f) { + gResolutions[gNumResolutions].width = mode.w; + gResolutions[gNumResolutions].height = mode.h; + gNumResolutions++; + } + } + + // Sort by area + qsort(gResolutions, gNumResolutions, sizeof(resolution), resolution_sort_func); + + // Remove duplicates + resPlace = &gResolutions[0]; + for (int i = 1; i < gNumResolutions; i++) { + resLook = &gResolutions[i]; + if (resLook->width != resPlace->width || resLook->height != resPlace->height) + *++resPlace = *resLook; + } + + gNumResolutions = (int)(resPlace - &gResolutions[0]) + 1; + + // Update config fullscreen resolution if not set + if (gConfigGeneral.fullscreen_width == -1 || gConfigGeneral.fullscreen_height == -1) { + gConfigGeneral.fullscreen_width = gResolutions[gNumResolutions - 1].width; + gConfigGeneral.fullscreen_height = gResolutions[gNumResolutions - 1].height; + } +} + +void platform_get_closest_resolution(int inWidth, int inHeight, int *outWidth, int *outHeight) +{ + int i, destinationArea, areaDiff, closestAreaDiff, closestWidth, closestHeight; + + closestAreaDiff = -1; + destinationArea = inWidth * inHeight; + for (i = 0; i < gNumResolutions; i++) { + // Check if exact match + if (gResolutions[i].width == inWidth && gResolutions[i].height == inHeight) { + closestWidth = gResolutions[i].width; + closestHeight = gResolutions[i].height; + closestAreaDiff = 0; + break; + } + + // Check if area is closer to best match + areaDiff = abs((gResolutions[i].width * gResolutions[i].height) - destinationArea); + if (closestAreaDiff == -1 || areaDiff < closestAreaDiff) { + closestAreaDiff = areaDiff; + closestWidth = gResolutions[i].width; + closestHeight = gResolutions[i].height; + } + } + + if (closestAreaDiff != -1) { + *outWidth = closestWidth; + *outHeight = closestHeight; + } else { + *outWidth = 640; + *outHeight = 480; + } +} + +void platform_draw() +{ + int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); + int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + + if (gConfigGeneral.hardware_display) { + void *pixels; + int pitch; + if (SDL_LockTexture(gBufferTexture, NULL, &pixels, &pitch) == 0) { + uint8 *src = (uint8*)_screenBuffer; + int padding = pitch - (width * 4); + if (pitch == width * 4) { + uint32 *dst = pixels; + for (int i = width * height; i > 0; i--) { *dst++ = *(uint32 *)(&gPaletteHWMapped[*src++]); } + } else + if (pitch == (width * 2) + padding) { + uint16 *dst = pixels; + for (int y = height; y > 0; y++) { + for (int x = width; x > 0; x--) { *dst++ = *(uint16 *)(&gPaletteHWMapped[*src++]); } + dst = (uint16*)(((uint8 *)dst) + padding); + } + } else + if (pitch == width + padding) { + uint8 *dst = pixels; + for (int y = height; y > 0; y++) { + for (int x = width; x > 0; x--) { *dst++ = *(uint8 *)(&gPaletteHWMapped[*src++]); } + dst += padding; + } + } + SDL_UnlockTexture(gBufferTexture); + } + + SDL_RenderCopy(gRenderer, gBufferTexture, NULL, NULL); + SDL_RenderPresent(gRenderer); + } else { + // Lock the surface before setting its pixels + if (SDL_MUSTLOCK(_surface)) { + if (SDL_LockSurface(_surface) < 0) { + log_error("locking failed %s", SDL_GetError()); + return; + } + } + + // Copy pixels from the virtual screen buffer to the surface + memcpy(_surface->pixels, _screenBuffer, _surface->pitch * _surface->h); + + // Unlock the surface + if (SDL_MUSTLOCK(_surface)) + SDL_UnlockSurface(_surface); + + // Copy the surface to the window + if (SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(gWindow), NULL)) { + log_fatal("SDL_BlitSurface %s", SDL_GetError()); + exit(1); + } + if (SDL_UpdateWindowSurface(gWindow)) { + log_fatal("SDL_UpdateWindowSurface %s", SDL_GetError()); + exit(1); + } + } +} + +static void platform_resize(int width, int height) +{ + uint32 flags; + + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) = width; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) = height; + + platform_refresh_video(); + + flags = SDL_GetWindowFlags(gWindow); + + if ((flags & SDL_WINDOW_MINIMIZED) == 0) { + window_resize_gui(width, height); + window_relocate_windows(width, height); + } + + gfx_invalidate_screen(); + + // Check if the window has been resized in windowed mode and update the config file accordingly + // This is called in rct2_update_2 and is only called after resizing a window has finished + if ((flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED | + SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) == 0) { + if (width != gConfigGeneral.window_width || height != gConfigGeneral.window_height) { + gConfigGeneral.window_width = width; + gConfigGeneral.window_height = height; + config_save_default(); + } + } +} + +void platform_update_palette(char* colours, int start_index, int num_colours) +{ + SDL_Surface *surface; + int i; + + for (i = 0; i < 256; i++) { + gPalette[i].r = colours[2]; + gPalette[i].g = colours[1]; + gPalette[i].b = colours[0]; + gPalette[i].a = 0; + colours += 4; + if (gBufferTextureFormat != NULL) { + gPaletteHWMapped[i] = SDL_MapRGB(gBufferTextureFormat, gPalette[i].r, gPalette[i].g, gPalette[i].b); + } + } + + if (!gOpenRCT2Headless && !gConfigGeneral.hardware_display) { + surface = SDL_GetWindowSurface(gWindow); + if (!surface) { + log_fatal("SDL_GetWindowSurface failed %s", SDL_GetError()); + exit(1); + } + + if (_palette != NULL && SDL_SetPaletteColors(_palette, gPalette, 0, 256)) { + log_fatal("SDL_SetPaletteColors failed %s", SDL_GetError()); + exit(1); + } + } +} + +void platform_process_messages() +{ + SDL_Event e; + + gLastKeyPressed = 0; + // gCursorState.wheel = 0; + gCursorState.left &= ~CURSOR_CHANGED; + gCursorState.middle &= ~CURSOR_CHANGED; + gCursorState.right &= ~CURSOR_CHANGED; + gCursorState.old = 0; + + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: +// rct2_finish(); + rct2_quit(); + break; + case SDL_WINDOWEVENT: + if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) + platform_resize(e.window.data1, e.window.data2); + break; + case SDL_MOUSEMOTION: + RCT2_GLOBAL(0x0142406C, int) = e.motion.x; + RCT2_GLOBAL(0x01424070, int) = e.motion.y; + + gCursorState.x = e.motion.x; + gCursorState.y = e.motion.y; + break; + case SDL_MOUSEWHEEL: + if (gConsoleOpen) { + console_scroll(e.wheel.y); + break; + } + gCursorState.wheel += e.wheel.y * 128; + break; + case SDL_MOUSEBUTTONDOWN: + RCT2_GLOBAL(0x01424318, int) = e.button.x; + RCT2_GLOBAL(0x0142431C, int) = e.button.y; + switch (e.button.button) { + case SDL_BUTTON_LEFT: + store_mouse_input(1); + gCursorState.left = CURSOR_PRESSED; + gCursorState.old = 1; + break; + case SDL_BUTTON_MIDDLE: + gCursorState.middle = CURSOR_PRESSED; + break; + case SDL_BUTTON_RIGHT: + store_mouse_input(3); + gCursorState.right = CURSOR_PRESSED; + gCursorState.old = 2; + break; + } + break; + case SDL_MOUSEBUTTONUP: + RCT2_GLOBAL(0x01424318, int) = e.button.x; + RCT2_GLOBAL(0x0142431C, int) = e.button.y; + switch (e.button.button) { + case SDL_BUTTON_LEFT: + store_mouse_input(2); + gCursorState.left = CURSOR_RELEASED; + gCursorState.old = 3; + break; + case SDL_BUTTON_MIDDLE: + gCursorState.middle = CURSOR_RELEASED; + break; + case SDL_BUTTON_RIGHT: + store_mouse_input(4); + gCursorState.right = CURSOR_RELEASED; + gCursorState.old = 4; + break; + } + break; + case SDL_KEYDOWN: + if (e.key.keysym.sym == SDLK_KP_ENTER){ + // Map Keypad enter to regular enter. + e.key.keysym.scancode = SDL_SCANCODE_RETURN; + } + + gLastKeyPressed = e.key.keysym.sym; + gKeysPressed[e.key.keysym.scancode] = 1; + if (e.key.keysym.sym == SDLK_RETURN && e.key.keysym.mod & KMOD_ALT) { + int targetMode = gConfigGeneral.fullscreen_mode == 0 ? 2 : 0; + platform_set_fullscreen_mode(targetMode); + gConfigGeneral.fullscreen_mode = targetMode; + config_save_default(); + break; + } + + // Text input + + // If backspace and we have input text with a cursor position none zero + if (e.key.keysym.sym == SDLK_BACKSPACE && gTextInputLength > 0 && gTextInput && gTextInputCursorPosition){ + // When at max length don't shift the data left + // as it would buffer overflow. + if (gTextInputCursorPosition != gTextInputMaxLength) + memmove(gTextInput + gTextInputCursorPosition - 1, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - 1); + gTextInput[gTextInputLength - 1] = '\0'; + gTextInputCursorPosition--; + gTextInputLength--; + console_refresh_caret(); + window_update_textbox(); + } + if (e.key.keysym.sym == SDLK_END){ + gTextInputCursorPosition = gTextInputLength; + console_refresh_caret(); + } + if (e.key.keysym.sym == SDLK_HOME){ + gTextInputCursorPosition = 0; + console_refresh_caret(); + } + if (e.key.keysym.sym == SDLK_DELETE && gTextInputLength > 0 && gTextInput && gTextInputCursorPosition != gTextInputLength){ + memmove(gTextInput + gTextInputCursorPosition, gTextInput + gTextInputCursorPosition + 1, gTextInputMaxLength - gTextInputCursorPosition - 1); + gTextInput[gTextInputMaxLength - 1] = '\0'; + gTextInputLength--; + console_refresh_caret(); + window_update_textbox(); + } + if (e.key.keysym.sym == SDLK_RETURN && gTextInput) { + window_cancel_textbox(); + } + if (e.key.keysym.sym == SDLK_LEFT && gTextInput){ + if (gTextInputCursorPosition) gTextInputCursorPosition--; + console_refresh_caret(); + } + else if (e.key.keysym.sym == SDLK_RIGHT && gTextInput){ + if (gTextInputCursorPosition < gTextInputLength) gTextInputCursorPosition++; + console_refresh_caret(); + } + // Checks GUI modifier key for Macs otherwise ctrl key +#ifdef MAC + else if (e.key.keysym.sym == SDLK_v && SDL_GetModState() & KMOD_GUI && gTextInput) { +#else + else if (e.key.keysym.sym == SDLK_v && SDL_GetModState() & KMOD_CTRL && gTextInput) { +#endif + if (SDL_HasClipboardText()) { + char* text = SDL_GetClipboardText(); + + for (int i = 0; text[i] != '\0' && gTextInputLength < gTextInputMaxLength; i++) { + // If inserting in center of string make space for new letter + if (gTextInputLength > gTextInputCursorPosition){ + memmove(gTextInput + gTextInputCursorPosition + 1, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - 1); + gTextInput[gTextInputCursorPosition] = text[i]; + gTextInputLength++; + } + else gTextInput[gTextInputLength++] = text[i]; + + gTextInputCursorPosition++; + } + window_update_textbox(); + } + } + break; + case SDL_MULTIGESTURE: + if (e.mgesture.numFingers == 2) { + if (e.mgesture.timestamp > _lastGestureTimestamp + 1000) + _gestureRadius = 0; + _lastGestureTimestamp = e.mgesture.timestamp; + _gestureRadius += e.mgesture.dDist; + + // Zoom gesture + const int tolerance = 128; + int gesturePixels = (int)(_gestureRadius * RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + if (gesturePixels > tolerance) { + _gestureRadius = 0; + keyboard_shortcut_handle_command(SHORTCUT_ZOOM_VIEW_IN); + } else if (gesturePixels < -tolerance) { + _gestureRadius = 0; + keyboard_shortcut_handle_command(SHORTCUT_ZOOM_VIEW_OUT); + } + } + break; + + case SDL_TEXTINPUT: + if (gTextInputLength < gTextInputMaxLength && gTextInput){ + // Convert the utf-8 code into rct ascii + char new_char; + if (e.text.text[0] == '`' && gConsoleOpen) + break; + if (!(e.text.text[0] & 0x80)) + new_char = *e.text.text; + else if (!(e.text.text[0] & 0x20)) + new_char = ((e.text.text[0] & 0x1F) << 6) | (e.text.text[1] & 0x3F); + + // If inserting in center of string make space for new letter + if (gTextInputLength > gTextInputCursorPosition){ + memmove(gTextInput + gTextInputCursorPosition + 1, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - 1); + gTextInput[gTextInputCursorPosition] = new_char; + gTextInputLength++; + } else { + gTextInput[gTextInputLength++] = new_char; + gTextInput[gTextInputLength] = 0; + } + + gTextInputCursorPosition++; + console_refresh_caret(); + window_update_textbox(); + } + break; + default: + break; + } + } + + gCursorState.any = gCursorState.left | gCursorState.middle | gCursorState.right; + + // Updates the state of the keys + int numKeys = 256; + gKeysState = SDL_GetKeyboardState(&numKeys); +} + +static void platform_close_window() +{ + if (gWindow != NULL) + SDL_DestroyWindow(gWindow); + if (_surface != NULL) + SDL_FreeSurface(_surface); + if (_palette != NULL) + SDL_FreePalette(_palette); + platform_unload_cursors(); +} + +void platform_init() +{ + platform_create_window(); + gKeysPressed = malloc(sizeof(unsigned char) * 256); + memset(gKeysPressed, 0, sizeof(unsigned char) * 256); +} + +static void platform_create_window() +{ + int width, height; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + log_fatal("SDL_Init %s", SDL_GetError()); + exit(-1); + } + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0); + + platform_load_cursors(); + + // TODO This should probably be called somewhere else. It has nothing to do with window creation and can be done as soon as + // g1.dat is loaded. + sub_68371D(); + + // Get window size + width = gConfigGeneral.window_width; + height = gConfigGeneral.window_height; + if (width == -1) width = 640; + if (height == -1) height = 480; + + RCT2_GLOBAL(0x009E2D8C, sint32) = 0; + + // Create window in window first rather than fullscreen so we have the display the window is on first + gWindow = SDL_CreateWindow( + "OpenRCT2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_RESIZABLE + ); + if (!gWindow) { + log_fatal("SDL_CreateWindow failed %s", SDL_GetError()); + exit(-1); + } + + // Set the update palette function pointer + RCT2_GLOBAL(0x009E2BE4, update_palette_func) = platform_update_palette; + + // Initialise the surface, palette and draw buffer + platform_resize(width, height); + + platform_update_fullscreen_resolutions(); + platform_set_fullscreen_mode(gConfigGeneral.fullscreen_mode); +} + +int platform_scancode_to_rct_keycode(int sdl_key) +{ + char keycode = (char)SDL_GetKeyFromScancode((SDL_Scancode)sdl_key); + + // Until we reshufle the text files to use the new positions + // this will suffice to move the majority to the correct positions. + // Note any special buttons PgUp PgDwn are mapped wrong. + if (keycode >= 'a' && keycode <= 'z') + keycode = toupper(keycode); + + return keycode; +} + +void platform_free() +{ + free(gKeysPressed); + + platform_close_window(); + SDL_Quit(); +} + +void platform_start_text_input(char* buffer, int max_length) +{ + SDL_StartTextInput(); + gTextInputMaxLength = max_length - 1; + gTextInput = buffer; + gTextInputCursorPosition = strnlen(gTextInput, max_length); + gTextInputLength = gTextInputCursorPosition; +} + +void platform_stop_text_input() +{ + SDL_StopTextInput(); + gTextInput = NULL; +} + +static void platform_unload_cursors() +{ + for (int i = 0; i < CURSOR_COUNT; i++) + if (_cursors[i] != NULL) + SDL_FreeCursor(_cursors[i]); +} + +void platform_set_fullscreen_mode(int mode) +{ + int width, height; + + mode = _fullscreen_modes[mode]; + + // HACK Changing window size when in fullscreen usually has no effect + if (mode == SDL_WINDOW_FULLSCREEN) + SDL_SetWindowFullscreen(gWindow, 0); + + // Set window size + if (mode == SDL_WINDOW_FULLSCREEN) { + platform_update_fullscreen_resolutions(); + platform_get_closest_resolution(gConfigGeneral.fullscreen_width, gConfigGeneral.fullscreen_height, &width, &height); + SDL_SetWindowSize(gWindow, width, height); + } else if (mode == 0) { + SDL_SetWindowSize(gWindow, gConfigGeneral.window_width, gConfigGeneral.window_height); + } + + if (SDL_SetWindowFullscreen(gWindow, mode)) { + log_fatal("SDL_SetWindowFullscreen %s", SDL_GetError()); + exit(1); + + // TODO try another display mode rather than just exiting the game + } +} + +/** + * This is not quite the same as the below function as we don't want to + * derfererence the cursor before the function. + * rct2: 0x0407956 + */ +void platform_set_cursor(char cursor) +{ + SDL_SetCursor(_cursors[cursor]); +} +/** + * + * rct2: 0x0068352C + */ +static void platform_load_cursors() +{ + RCT2_GLOBAL(0x14241BC, uint32) = 2; + HINSTANCE hInst = RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_ARROW, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x74)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_BLANK, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0xA1)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_UP_ARROW, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x6D)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_UP_DOWN_ARROW, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x6E)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HAND_POINT, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x70)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_ZZZ, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x78)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_DIAGONAL_ARROWS, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x77)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_PICKER, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x7C)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_TREE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x83)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_FOUNTAIN_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x7F)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_STATUE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x80)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_BENCH_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x81)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_CROSS_HAIR, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x82)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_BIN_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x84)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_LAMPPOST_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x85)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_FENCE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8A)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_FLOWER_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x89)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_PATH_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8B)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_DIG_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8D)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_WATER_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8E)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HOUSE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x8F)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_VOLCANO_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x90)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_WALK_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x91)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_PAINT_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x9E)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_ENTRANCE_DOWN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0x9F)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HAND_OPEN, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0xA6)); + RCT2_GLOBAL(RCT2_ADDRESS_HCURSOR_HAND_CLOSED, HCURSOR) = LoadCursor(hInst, MAKEINTRESOURCE(0xA5)); + + _cursors[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + _cursors[1] = SDL_CreateCursor(blank_cursor_data, blank_cursor_mask, 32, 32, BLANK_CURSOR_HOTX, BLANK_CURSOR_HOTY); + _cursors[2] = SDL_CreateCursor(up_arrow_cursor_data, up_arrow_cursor_mask, 32, 32, UP_ARROW_CURSOR_HOTX, UP_ARROW_CURSOR_HOTY); + _cursors[3] = SDL_CreateCursor(up_down_arrow_cursor_data, up_down_arrow_cursor_mask, 32, 32, UP_DOWN_ARROW_CURSOR_HOTX, UP_DOWN_ARROW_CURSOR_HOTY); + _cursors[4] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); + _cursors[5] = SDL_CreateCursor(zzz_cursor_data, zzz_cursor_mask, 32, 32, ZZZ_CURSOR_HOTX, ZZZ_CURSOR_HOTY); + _cursors[6] = SDL_CreateCursor(diagonal_arrow_cursor_data, diagonal_arrow_cursor_mask, 32, 32, DIAGONAL_ARROW_CURSOR_HOTX, DIAGONAL_ARROW_CURSOR_HOTY); + _cursors[7] = SDL_CreateCursor(picker_cursor_data, picker_cursor_mask, 32, 32, PICKER_CURSOR_HOTX, PICKER_CURSOR_HOTY); + _cursors[8] = SDL_CreateCursor(tree_down_cursor_data, tree_down_cursor_mask, 32, 32, TREE_DOWN_CURSOR_HOTX, TREE_DOWN_CURSOR_HOTY); + _cursors[9] = SDL_CreateCursor(fountain_down_cursor_data, fountain_down_cursor_mask, 32, 32, FOUNTAIN_DOWN_CURSOR_HOTX, FOUNTAIN_DOWN_CURSOR_HOTY); + _cursors[10] = SDL_CreateCursor(statue_down_cursor_data, statue_down_cursor_mask, 32, 32, STATUE_DOWN_CURSOR_HOTX, STATUE_DOWN_CURSOR_HOTY); + _cursors[11] = SDL_CreateCursor(bench_down_cursor_data, bench_down_cursor_mask, 32, 32, BENCH_DOWN_CURSOR_HOTX, BENCH_DOWN_CURSOR_HOTY); + _cursors[12] = SDL_CreateCursor(cross_hair_cursor_data, cross_hair_cursor_mask, 32, 32, CROSS_HAIR_CURSOR_HOTX, CROSS_HAIR_CURSOR_HOTY); + _cursors[13] = SDL_CreateCursor(bin_down_cursor_data, bin_down_cursor_mask, 32, 32, BIN_DOWN_CURSOR_HOTX, BIN_DOWN_CURSOR_HOTY); + _cursors[14] = SDL_CreateCursor(lamppost_down_cursor_data, lamppost_down_cursor_mask, 32, 32, LAMPPOST_DOWN_CURSOR_HOTX, LAMPPOST_DOWN_CURSOR_HOTY); + _cursors[15] = SDL_CreateCursor(fence_down_cursor_data, fence_down_cursor_mask, 32, 32, FENCE_DOWN_CURSOR_HOTX, FENCE_DOWN_CURSOR_HOTY); + _cursors[16] = SDL_CreateCursor(flower_down_cursor_data, flower_down_cursor_mask, 32, 32, FLOWER_DOWN_CURSOR_HOTX, FLOWER_DOWN_CURSOR_HOTY); + _cursors[17] = SDL_CreateCursor(path_down_cursor_data, path_down_cursor_mask, 32, 32, PATH_DOWN_CURSOR_HOTX, PATH_DOWN_CURSOR_HOTY); + _cursors[18] = SDL_CreateCursor(dig_down_cursor_data, dig_down_cursor_mask, 32, 32, DIG_DOWN_CURSOR_HOTX, DIG_DOWN_CURSOR_HOTY); + _cursors[19] = SDL_CreateCursor(water_down_cursor_data, water_down_cursor_mask, 32, 32, WATER_DOWN_CURSOR_HOTX, WATER_DOWN_CURSOR_HOTY); + _cursors[20] = SDL_CreateCursor(house_down_cursor_data, house_down_cursor_mask, 32, 32, HOUSE_DOWN_CURSOR_HOTX, HOUSE_DOWN_CURSOR_HOTY); + _cursors[21] = SDL_CreateCursor(volcano_down_cursor_data, volcano_down_cursor_mask, 32, 32, VOLCANO_DOWN_CURSOR_HOTX, VOLCANO_DOWN_CURSOR_HOTY); + _cursors[22] = SDL_CreateCursor(walk_down_cursor_data, walk_down_cursor_mask, 32, 32, WALK_DOWN_CURSOR_HOTX, WALK_DOWN_CURSOR_HOTY); + _cursors[23] = SDL_CreateCursor(paint_down_cursor_data, paint_down_cursor_mask, 32, 32, PAINT_DOWN_CURSOR_HOTX, PAINT_DOWN_CURSOR_HOTY); + _cursors[24] = SDL_CreateCursor(entrance_down_cursor_data, entrance_down_cursor_mask, 32, 32, ENTRANCE_DOWN_CURSOR_HOTX, ENTRANCE_DOWN_CURSOR_HOTY); + _cursors[25] = SDL_CreateCursor(hand_open_cursor_data, hand_open_cursor_mask, 32, 32, HAND_OPEN_CURSOR_HOTX, HAND_OPEN_CURSOR_HOTY); + _cursors[26] = SDL_CreateCursor(hand_closed_cursor_data, hand_closed_cursor_mask, 32, 32, HAND_CLOSED_CURSOR_HOTX, HAND_CLOSED_CURSOR_HOTY); + platform_set_cursor(CURSOR_ARROW); + RCT2_GLOBAL(0x14241BC, uint32) = 0; +} + +/** + * + * rct2: 0x00407D80 + */ +int platform_get_cursor_pos(int* x, int* y) +{ + POINT point; + GetCursorPos(&point); + *x = point.x; + *y = point.y; +} + +void platform_refresh_video() +{ + int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); + int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + + if (gConfigGeneral.hardware_display) { + if (gRenderer == NULL) + gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED); + + if (gBufferTexture != NULL) + SDL_DestroyTexture(gBufferTexture); + + if (gBufferTextureFormat != NULL) + SDL_FreeFormat(gBufferTextureFormat); + + SDL_RendererInfo rendererinfo; + SDL_GetRendererInfo(gRenderer, &rendererinfo); + Uint32 pixelformat = SDL_PIXELFORMAT_UNKNOWN; + for(unsigned int i = 0; i < rendererinfo.num_texture_formats; i++){ + Uint32 format = rendererinfo.texture_formats[i]; + if(!SDL_ISPIXELFORMAT_FOURCC(format) && !SDL_ISPIXELFORMAT_INDEXED(format) && (pixelformat == SDL_PIXELFORMAT_UNKNOWN || SDL_BYTESPERPIXEL(format) < SDL_BYTESPERPIXEL(pixelformat))){ + pixelformat = format; + } + } + + gBufferTexture = SDL_CreateTexture(gRenderer, pixelformat, SDL_TEXTUREACCESS_STREAMING, width, height); + Uint32 format; + SDL_QueryTexture(gBufferTexture, &format, 0, 0, 0); + gBufferTextureFormat = SDL_AllocFormat(format); + platform_refresh_screenbuffer(width, height, width); + } else { + if (_surface != NULL) + SDL_FreeSurface(_surface); + if (_palette != NULL) + SDL_FreePalette(_palette); + + _surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0); + _palette = SDL_AllocPalette(256); + + if (!_surface || !_palette) { + log_fatal("%p || %p == NULL %s", _surface, _palette, SDL_GetError()); + exit(-1); + } + + if (SDL_SetSurfacePalette(_surface, _palette)) { + log_fatal("SDL_SetSurfacePalette failed %s", SDL_GetError()); + exit(-1); + } + + platform_refresh_screenbuffer(width, height, _surface->pitch); + } +} + +static void platform_refresh_screenbuffer(int width, int height, int pitch) +{ + int newScreenBufferSize = pitch * height; + char *newScreenBuffer = (char*)malloc(newScreenBufferSize); + if (_screenBuffer == NULL) { + memset(newScreenBuffer, 0, newScreenBufferSize); + } else { + if (_screenBufferPitch == pitch) { + memcpy(newScreenBuffer, _screenBuffer, min(_screenBufferSize, newScreenBufferSize)); + } else { + char *src = _screenBuffer; + char *dst = newScreenBuffer; + + int minWidth = min(_screenBufferWidth, width); + int minHeight = min(_screenBufferHeight, height); + for (int y = 0; y < minHeight; y++) { + memcpy(dst, src, minWidth); + if (pitch - minWidth > 0) + memset(dst + minWidth, 0, pitch - minWidth); + + src += _screenBufferPitch; + dst += pitch; + } + } + //if (newScreenBufferSize - _screenBufferSize > 0) + // memset((uint8*)newScreenBuffer + _screenBufferSize, 0, newScreenBufferSize - _screenBufferSize); + free(_screenBuffer); + } + + _screenBuffer = newScreenBuffer; + _screenBufferSize = newScreenBufferSize; + _screenBufferWidth = width; + _screenBufferHeight = height; + _screenBufferPitch = pitch; + + rct_drawpixelinfo *screenDPI; + screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); + screenDPI->bits = _screenBuffer; + screenDPI->x = 0; + screenDPI->y = 0; + screenDPI->width = width; + screenDPI->height = height; + screenDPI->pitch = _screenBufferPitch - width; + + RCT2_GLOBAL(0x009ABDF0, uint8) = 6; + RCT2_GLOBAL(0x009ABDF1, uint8) = 3; + RCT2_GLOBAL(0x009ABDF2, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16) = 64; + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16) = 8; + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) = (width >> 6) + 1; + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32) = (height >> 3) + 1; +} \ No newline at end of file diff --git a/src/platform/windows.c b/src/platform/windows.c index c258dbcc77..b090bae968 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -21,9 +21,14 @@ #ifdef _WIN32 #include +#include +#include #include "../addresses.h" #include "../cmdline.h" #include "../openrct2.h" +#include "../localisation/language.h" +#include "../localisation/currency.h" +#include "../config.h" #include "platform.h" // The name of the mutex used to prevent multiple instances of the game from running @@ -70,11 +75,12 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta // Get command line arguments in standard form argv = CommandLineToArgvA(lpCmdLine, &argc); runGame = cmdline_run(argv, argc); - LocalFree(argv); + GlobalFree(argv); if (runGame) openrct2_launch(); + exit(gExitCode); return gExitCode; } @@ -112,7 +118,7 @@ int platform_lock_single_instance() // Create new mutex status = CreateMutex(NULL, FALSE, SINGLE_INSTANCE_MUTEX_NAME); if (status == NULL) - fprintf(stderr, "unable to create mutex\n"); + log_error("unable to create mutex\n"); return 1; } else { @@ -190,6 +196,90 @@ void platform_enumerate_files_end(int handle) enumFileInfo->active = 0; } +int platform_enumerate_directories_begin(const char *directory) +{ + int i; + enumerate_file_info *enumFileInfo; + + if (strlen(directory) + 3 >= MAX_PATH) + return INVALID_HANDLE; + + for (i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + strncpy(enumFileInfo->pattern, directory, MAX_PATH); + strncat(enumFileInfo->pattern, "*", MAX_PATH); + enumFileInfo->handle = NULL; + enumFileInfo->active = 1; + return i; + } + } + + return INVALID_HANDLE; +} + +int platform_enumerate_directories_next(int handle, char *path) +{ + enumerate_file_info *enumFileInfo; + HANDLE fileHandle; + + enumFileInfo = &_enumerateFileInfoList[handle]; + + if (enumFileInfo->handle == NULL) { + fileHandle = FindFirstFile(enumFileInfo->pattern, &enumFileInfo->data); + if (fileHandle != 0) { + enumFileInfo->handle = fileHandle; + } else { + return 0; + } + } else { + if (!FindNextFile(enumFileInfo->handle, &enumFileInfo->data)) { + return 0; + } + } + + while ( + (enumFileInfo->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 + || strchr(enumFileInfo->data.cFileName, '.') != NULL + ) { + if (!FindNextFile(enumFileInfo->handle, &enumFileInfo->data)) { + return 0; + } + } + + memset(path, '\0', MAX_PATH); + strncpy(path, enumFileInfo->data.cFileName, MAX_PATH); + strncat(path, "\\", MAX_PATH); + return 1; +} + +void platform_enumerate_directories_end(int handle) +{ + enumerate_file_info *enumFileInfo; + + enumFileInfo = &_enumerateFileInfoList[handle]; + if (enumFileInfo->handle != NULL) { + FindClose(enumFileInfo->handle); + enumFileInfo->handle = NULL; + } + enumFileInfo->active = 0; +} + +int platform_file_copy(const char *srcPath, const char *dstPath) +{ + return CopyFileA(srcPath, dstPath, TRUE); +} + +int platform_file_move(const char *srcPath, const char *dstPath) +{ + return MoveFileA(srcPath, dstPath); +} + +int platform_file_delete(const char *path) +{ + return DeleteFileA(path); +} + void platform_hide_cursor() { ShowCursor(FALSE); @@ -223,6 +313,203 @@ unsigned int platform_get_ticks() return GetTickCount(); } +void platform_get_user_directory(char *outPath, const char *subDirectory) +{ + char seperator[2] = { platform_get_path_separator(), 0 }; + + if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, outPath))) { + strcat(outPath, seperator); + strcat(outPath, "OpenRCT2"); + strcat(outPath, seperator); + if (subDirectory != NULL && subDirectory[0] != 0) { + strcat(outPath, subDirectory); + strcat(outPath, seperator); + } + } else { + outPath[0] = 0; + } +} + +void platform_show_messagebox(char *message) +{ + MessageBoxA(windows_get_window_handle(), message, "OpenRCT2", MB_OK); +} + +/** + * + * rct2: 0x004080EA + */ +int platform_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName) +{ + char initialDirectory[MAX_PATH], *dotAddress, *slashAddress; + OPENFILENAME openFileName; + BOOL result; + int tmp; + DWORD commonFlags; + + // Get directory path from given filename + strcpy(initialDirectory, filename); + dotAddress = strrchr(initialDirectory, '.'); + if (dotAddress != NULL) { + slashAddress = strrchr(initialDirectory, '\\'); + if (slashAddress < dotAddress) + *(slashAddress + 1) = 0; + } + + // Clear filename + if (type != 0) + *filename = 0; + + // Set open file name options + memset(&openFileName, 0, sizeof(OPENFILENAME)); + openFileName.lStructSize = sizeof(OPENFILENAME); + openFileName.hwndOwner = windows_get_window_handle(); + openFileName.lpstrFile = filename; + openFileName.nMaxFile = MAX_PATH; + openFileName.lpstrInitialDir = initialDirectory; + openFileName.lpstrTitle = title; + + // Copy filter name + strcpy((char*)0x01423800, filterName); + + // Copy filter pattern + strcpy((char*)0x01423800 + strlen(filterName) + 1, filterPattern); + *((char*)(0x01423800 + strlen(filterName) + 1 + strlen(filterPattern) + 1)) = 0; + openFileName.lpstrFilter = (char*)0x01423800; + + // + tmp = RCT2_GLOBAL(0x009E2C74, uint32); + if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1) + RCT2_GLOBAL(0x009E2C74, uint32) = 1; + + // Open dialog + commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + if (type == 0) { + openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT; + result = GetSaveFileName(&openFileName); + } else if (type == 1) { + openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST; + result = GetOpenFileName(&openFileName); + } + + // + RCT2_GLOBAL(0x009E2C74, uint32) = tmp; + + return result; +} + +char *platform_open_directory_browser(char *title) +{ + BROWSEINFO bi; + char pszBuffer[MAX_PATH]; + LPITEMIDLIST pidl; + LPMALLOC lpMalloc; + + // Initialize COM + if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED))) { + CoUninitialize(); + + log_error("Error opening directory browse window"); + return 0; + } + + // Get a pointer to the shell memory allocator + if (FAILED(SHGetMalloc(&lpMalloc))) { + CoUninitialize(); + + log_error("Error opening directory browse window"); + return 0; + } + + bi.hwndOwner = NULL; + bi.pidlRoot = NULL; + bi.pszDisplayName = pszBuffer; + bi.lpszTitle = title; + bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS; + bi.lpfn = NULL; + bi.lParam = 0; + + char *outPath = NULL; + + if (pidl = SHBrowseForFolder(&bi)) { + // Copy the path directory to the buffer + if (SHGetPathFromIDList(pidl, pszBuffer)) { + // Store pszBuffer (and the path) in the outPath + outPath = (char*) malloc(strlen(pszBuffer)+1); + strcpy(outPath, pszBuffer); + } + } + CoUninitialize(); + return outPath; +} + +/** + * + * rct2: 0x00407978 + */ +int windows_get_registry_install_info(rct2_install_info *installInfo, char *source, char *font, uint8 charset) +{ + char subkeyInfogrames[MAX_PATH], subkeyFishTechGroup[MAX_PATH], keyName[100]; + LOGFONTA lf; + HKEY hKey; + DWORD type, size; + + strcpy(subkeyInfogrames, "Software\\Infogrames\\"); + strcat(subkeyInfogrames, source); + strcpy(subkeyFishTechGroup, "Software\\Fish Technology Group\\"); + strcat(subkeyFishTechGroup, source); + + memset(&lf, 0, sizeof(lf)); + lf.lfCharSet = charset; + lf.lfHeight = 12; + lf.lfWeight = 400; + strcpy(lf.lfFaceName, font); + + RCT2_GLOBAL(RCT2_ADDRESS_HFONT, HFONT) = CreateFontIndirectA(&lf); + + if (RegOpenKeyA(HKEY_LOCAL_MACHINE, subkeyInfogrames, &hKey) != ERROR_SUCCESS) + return 0; + + if (RegOpenKeyA(HKEY_LOCAL_MACHINE, subkeyFishTechGroup, &hKey) != ERROR_SUCCESS) + return 0; + + + size = 260; + RegQueryValueExA(hKey, "Title", 0, &type, installInfo->title, &size); + + size = 260; + RegQueryValueExA(hKey, "Path", 0, &type, installInfo->path, &size); + + installInfo->var_20C = 235960; + + size = 4; + RegQueryValueExA(hKey, "InstallLevel", 0, &type, (LPBYTE)&installInfo->installLevel, &size); + for (int i = 0; i <= 15; i++) { + sprintf(keyName, "AddonPack%d", i); + size = sizeof(installInfo->expansionPackNames[i]); + if (RegQueryValueExA(hKey, keyName, 0, &type, installInfo->expansionPackNames[i], &size) == ERROR_SUCCESS) + installInfo->activeExpansionPacks |= (1 << i); + } + + RegCloseKey(hKey); + return 1; +} + +HWND windows_get_window_handle() +{ + SDL_SysWMinfo wmInfo; + + if (gWindow == NULL) + return NULL; + + SDL_VERSION(&wmInfo.version); + if (SDL_GetWindowWMInfo(gWindow, &wmInfo) != SDL_TRUE) { + log_error("SDL_GetWindowWMInfo failed %s", SDL_GetError()); + exit(-1); + } + return wmInfo.info.win.window; +} + /** * http://alter.org.ua/en/docs/win/args/ */ @@ -243,11 +530,13 @@ PCHAR *CommandLineToArgvA(PCHAR CmdLine, int *_argc) i = ((len + 2) / 2)*sizeof(PVOID) + sizeof(PVOID); argv = (PCHAR*)GlobalAlloc(GMEM_FIXED, - i + (len + 2)*sizeof(CHAR)); + i + (len + 2)*sizeof(CHAR) + 1); _argv = (PCHAR)(((PUCHAR)argv) + i); - argc = 0; + // Add in virtual 1st command line argument, process path, for arg_parse's sake. + argv[0] = 0; + argc = 1; argv[argc] = _argv; in_QM = FALSE; in_TEXT = FALSE; @@ -306,4 +595,123 @@ PCHAR *CommandLineToArgvA(PCHAR CmdLine, int *_argc) return argv; } -#endif \ No newline at end of file +uint16 platform_get_locale_language(){ + CHAR langCode[4]; + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SABBREVLANGNAME, + (LPSTR)&langCode, + sizeof(langCode)) == 0){ + return LANGUAGE_UNDEFINED; + } + + if (strcmp(langCode, "ENG") == 0){ + return LANGUAGE_ENGLISH_UK; + } + else if (strcmp(langCode, "ENU") == 0){ + return LANGUAGE_ENGLISH_US; + } + else if (strcmp(langCode, "DEU") == 0){ + return LANGUAGE_GERMAN; + } + else if (strcmp(langCode, "NLD") == 0){ + return LANGUAGE_DUTCH; + } + else if (strcmp(langCode, "FRA") == 0){ + return LANGUAGE_FRENCH; + } + else if (strcmp(langCode, "HUN") == 0){ + return LANGUAGE_HUNGARIAN; + } + else if (strcmp(langCode, "PLK") == 0){ + return LANGUAGE_POLISH; + } + else if (strcmp(langCode, "ESP") == 0){ + return LANGUAGE_SPANISH; + } + else if (strcmp(langCode, "SVE") == 0){ + return LANGUAGE_SWEDISH; + } + else if (strcmp(langCode, "ITA") == 0){ + return LANGUAGE_ITALIAN; + } + return LANGUAGE_UNDEFINED; +} + +uint8 platform_get_locale_currency(){ + CHAR currCode[4]; + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SINTLSYMBOL, + (LPSTR)&currCode, + sizeof(currCode)) == 0){ + return CURRENCY_POUNDS; + } + if (strcmp(currCode, "GBP") == 0){ + return CURRENCY_POUNDS; + } + else if (strcmp(currCode, "USD") == 0){ + return CURRENCY_DOLLARS; + } + else if (strcmp(currCode, "EUR") == 0){ + return CURRENCY_EUROS; + } + else if (strcmp(currCode, "SEK") == 0){ + return CURRENCY_KRONA; + } + else if (strcmp(currCode, "DEM") == 0){ + return CURRENCY_DEUTSCHMARK; + } + else if (strcmp(currCode, "ITL") == 0){ + return CURRENCY_LIRA; + } + else if (strcmp(currCode, "JPY") == 0){ + return CURRENCY_YEN; + } + else if (strcmp(currCode, "ESP") == 0){ + return CURRENCY_PESETA; + } + else if (strcmp(currCode, "FRF") == 0){ + return CURRENCY_FRANC; + } + else if (strcmp(currCode, "NLG") == 0){ + return CURRENCY_GUILDERS; + } + return CURRENCY_POUNDS; +} + +uint8 platform_get_locale_measurement_format(){ + UINT measurement_system; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, + (LPSTR)&measurement_system, + sizeof(measurement_system)) == 0){ + return MEASUREMENT_FORMAT_IMPERIAL; + } + switch (measurement_system){ + case 0: + return MEASUREMENT_FORMAT_METRIC; + case 1: + default: + return MEASUREMENT_FORMAT_IMPERIAL; + } +} + +uint8 platform_get_locale_temperature_format(){ + // There does not seem to be a function to obtain this, just check the countries + UINT country; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, + (LPSTR)&country, + sizeof(country)) == 0){ + return TEMPERATURE_FORMAT_C; + } + switch (country){ + case CTRY_UNITED_STATES: + case CTRY_BELIZE: + return TEMPERATURE_FORMAT_F; + default: + return TEMPERATURE_FORMAT_C; + } +} +#endif diff --git a/src/rct1.c b/src/rct1.c new file mode 100644 index 0000000000..794507fec8 --- /dev/null +++ b/src/rct1.c @@ -0,0 +1,1105 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#include "addresses.h" +#include "interface/viewport.h" +#include "interface/window.h" +#include "localisation/localisation.h" +#include "management/finance.h" +#include "object.h" +#include "rct1.h" +#include "scenario.h" +#include "util/sawyercoding.h" +#include "util/util.h" +#include "world/climate.h" +#include "world/map.h" +#include "world/scenery.h" + +typedef struct { + const rct_object_entry* entries; + int count; +} RCT1DefaultObjectsGroup; + +const uint8 RCT1TerrainConvertTable[16]; +const uint8 RCT1TerrainEdgeConvertTable[16]; +static const RCT1DefaultObjectsGroup RCT1DefaultObjects[10]; + +static void rct1_remove_rides(); +static void rct1_load_default_objects(); +static void rct1_fix_terrain(); +static void rct1_fix_scenery(); +static void rct1_fix_entrance_positions(); +static void rct1_reset_research(); + +static void sub_69F06A(); +static void sub_666DFD(); + +static void read(void *dst, void *src, int length) +{ + memcpy(dst, src, length); +} + +bool rct1_read_sc4(const char *path, rct1_s4 *s4) +{ + char *buffer, *decodedBuffer; + long length, decodedLength; + bool success; + + if (!readentirefile(path, (void**)&buffer, &length)) { + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3011; + return 0; + } + + int fileType = sawyercoding_detect_file_type(buffer, length); + + decodedBuffer = malloc(sizeof(rct1_s4)); + decodedLength = (fileType & FILE_VERSION_MASK) == FILE_VERSION_RCT1 ? + sawyercoding_decode_sv4(buffer, decodedBuffer, length) : + sawyercoding_decode_sc4(buffer, decodedBuffer, length); + if (decodedLength == sizeof(rct1_s4)) { + memcpy(s4, decodedBuffer, sizeof(rct1_s4)); + success = true; + } else { + success = false; + } + + free(buffer); + free(decodedBuffer); + return success; +} + +bool rct1_read_sv4(const char *path, rct1_s4 *s4) +{ + char *buffer, *decodedBuffer; + long length, decodedLength; + bool success; + + if (!readentirefile(path, (void**)&buffer, &length)) { + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3011; + return 0; + } + + decodedBuffer = malloc(sizeof(rct1_s4)); + decodedLength = sawyercoding_decode_sv4(buffer, decodedBuffer, length); + if (decodedLength == sizeof(rct1_s4)) { + memcpy(s4, decodedBuffer, sizeof(rct1_s4)); + success = true; + } else { + success = false; + } + + free(buffer); + free(decodedBuffer); + return success; +} + +/** + * + * rct2: 0x0069EEA0 + */ +void rct1_import_s4(rct1_s4 *s4) +{ + int i; + rct_banner *banner; + + read((void*)RCT2_ADDRESS_CURRENT_MONTH_YEAR, &s4->month, 16); + memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, 0x30000 * sizeof(rct_map_element)); + read((void*)RCT2_ADDRESS_MAP_ELEMENTS, s4->map_elements, sizeof(s4->map_elements)); + read((void*)0x010E63B8, &s4->unk_counter, 4 + sizeof(s4->sprites)); + + for (i = 0; i < MAX_BANNERS; i++) + gBanners[i].type = 255; + + read((void*)0x013573BC, &s4->next_sprite_index, 12424); + + for (i = 0; i < MAX_BANNERS; i++) { + banner = &gBanners[i]; + if (banner->type != 255 && banner->string_idx != 3458) + banner->string_idx = 778; + } + + read((void*)0x0135A8F4, &s4->string_table, 0x2F51C); + memset((void*)0x013CA672, 0, 204); + read((void*)0x0138B580, &s4->map_animations, 0x258F2); + read((void*)0x013C6A72, &s4->patrol_areas, sizeof(s4->patrol_areas)); + + 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, &s4->unk_1F42AA, 116); + read((void*)0x013CA73A, &s4->unk_1F431E, 4); + read((void*)0x013CA73E, &s4->unk_1F4322, 0x41EA); +} + +/** + * + * rct2: 0x006A2B62 + */ +void rct1_fix_landscape() +{ + int i; + rct_sprite *sprite; + rct_ride *ride; + + RCT2_CALLPROC_EBPSAFE(0x0069F007); + + // Free sprite user strings + for (i = 0; i < MAX_SPRITES; i++) { + sprite = &g_sprite_list[i]; + if (sprite->unknown.sprite_identifier != 255) + user_string_free(sprite->unknown.name_string_idx); + } + + reset_sprite_list(); + + // Free ride user strings + FOR_ALL_RIDES(i, ride) + user_string_free(ride->name); + + ride_init_all(); + RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16) = 0; + RCT2_GLOBAL(0x01357BC8, uint16) = 0; + RCT2_GLOBAL(0x013573FE, uint8) = 0; + RCT2_CALLPROC_EBPSAFE(0x0069F44B); + sub_69F06A(); + RCT2_CALLPROC_EBPSAFE(0x0069F143); + RCT2_CALLPROC_EBPSAFE(0x0069F2D0); + RCT2_CALLPROC_EBPSAFE(0x0069F3AB); + rct1_remove_rides(); + object_unload_all(); + rct1_load_default_objects(); + reset_loaded_objects(); + RCT2_CALLPROC_EBPSAFE(0x006A2730); + rct1_fix_scenery(); + rct1_fix_terrain(); + rct1_fix_entrance_positions(); + rct1_reset_research(); + research_populate_list_random(); + research_remove_non_separate_vehicle_types(); + + climate_reset(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8)); + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR; + viewport_init_all(); + news_item_init_queue(); + window_editor_main_open(); + + rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + + s6Info->var_000 = 1; + s6Info->category = 4; + format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); + s6Info->name[0] = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY_SCENARIO; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_NO_MONEY_SCENARIO; + } + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) == MONEY_FREE) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_FREE_ENTRY; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_PARK_FREE_ENTRY; + } + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18; + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) = clamp( + MONEY(10,00), + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16), + MONEY(100,00) + ); + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) = min( + MONEY(10000,00), + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) + ); + RCT2_CALLPROC_EBPSAFE(0x0069E89B); + sub_69E869(); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp( + MONEY(0,00), + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32), + MONEY(5000000,00) + ); + + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = clamp( + MONEY(0,00), + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32), + MONEY(5000000,00) + ); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, uint8) = clamp( + 5, + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, uint8), + 80 + ); + + if ( + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_NONE || + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_HAVE_FUN || + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_BUILD_THE_BEST + ) { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) = OBJECTIVE_GUESTS_BY; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) = 4; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) = 1000; + } + + RCT2_GLOBAL(0x01358774, uint16) = 0; +} + +static void rct1_remove_rides() +{ + map_element_iterator it; + + map_element_iterator_begin(&it); + do { + switch (map_element_get_type(it.element)) { + case MAP_ELEMENT_TYPE_PATH: + if (it.element->type & 1) { + it.element->properties.path.type &= 0xF7; + it.element->properties.path.addition_status = 255; + } + break; + + case MAP_ELEMENT_TYPE_TRACK: + sub_6A7594(); + sub_6A6AA7(it.x * 32, it.y * 32, it.element); + map_element_remove(it.element); + map_element_iterator_restart_for_tile(&it); + break; + + case MAP_ELEMENT_TYPE_ENTRANCE: + if (it.element->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) { + sub_6A7594(); + sub_6A6AA7(it.x * 32, it.y * 32, it.element); + map_element_remove(it.element); + map_element_iterator_restart_for_tile(&it); + } + break; + } + } while (map_element_iterator_next(&it)); +} + +/** + * + * rct2: 0x0069F53D + */ +static void rct1_load_default_objects() +{ + for (int i = 0; i < 9; i++) { + rct_object_entry *entries = (rct_object_entry*)RCT1DefaultObjects[i].entries; + for (int j = 0; j < RCT1DefaultObjects[i].count; j++) { + if (!object_load(j, &entries[j], NULL)) { + error_string_quit(0x99990000 + (i * 0x100) + j, -1); + return; + } + } + } + + // Water is a special case + rct_object_entry *waterEntries = (rct_object_entry*)RCT1DefaultObjects[9].entries; + rct_object_entry *waterEntry = &waterEntries[RCT2_GLOBAL(0x01358841, uint8) == 0 ? 0 : 1]; + if (!object_load(0, waterEntry, NULL)) { + error_string_quit(0x99990900, -1); + return; + } +} + +/** + * + * rct2: 0x006A29B9 + */ +static void rct1_fix_terrain() +{ + rct_map_element *element; + map_element_iterator it; + + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) { + element = it.element; + + if (map_element_get_type(element) != MAP_ELEMENT_TYPE_SURFACE) + continue; + + // Convert terrain + map_element_set_terrain(element, RCT1TerrainConvertTable[map_element_get_terrain(element)]); + map_element_set_terrain_edge(element, RCT1TerrainEdgeConvertTable[map_element_get_terrain_edge(element)]); + } +} + +/** + * + * rct2: 0x006A2956 + */ +static void rct1_fix_scenery() +{ + rct_map_element *element; + map_element_iterator it; + + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) { + element = it.element; + + if (map_element_get_type(element) != MAP_ELEMENT_TYPE_SCENERY) + continue; + + switch (element->properties.scenery.type) { + case 157: // TGE1 (Geometric Sculpture) + case 162: // TGE2 (Geometric Sculpture) + case 168: // TGE3 (Geometric Sculpture) + case 170: // TGE4 (Geometric Sculpture) + case 171: // TGE5 (Geometric Sculpture) + element->properties.scenery.colour_2 = 2; + break; + } + } +} + +/** + * This isn't really RCT1 specific anymore. + * rct2: 0x006A2A68 + */ +static void rct1_fix_entrance_positions() +{ + rct_map_element *element; + map_element_iterator it; + + for (int i = 0; i < 4; i++) + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] = 0x8000; + + int entranceIndex = 0; + + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) { + element = it.element; + + if (map_element_get_type(element) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (element->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + if ((element->properties.entrance.index & 0x0F) != 0) + continue; + + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[entranceIndex] = it.x * 32; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, uint16)[entranceIndex] = it.y * 32; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, uint16)[entranceIndex] = element->base_height * 8; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[entranceIndex] = element->type & 3; + entranceIndex++; + + // Prevent overflow + if (entranceIndex == 4) + return; + } +} + +/** + * + * rct2: 0x0069F509 + */ +static void rct1_reset_research() +{ + rct_research_item *researchItem; + + researchItem = gResearchItems; + researchItem->entryIndex = RESEARCHED_ITEMS_SEPERATOR; + researchItem++; + researchItem->entryIndex = RESEARCHED_ITEMS_END; + researchItem++; + researchItem->entryIndex = RESEARCHED_ITEMS_END_2; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = 0; + RCT2_GLOBAL(0x01357CF4, sint32) = -1; + news_item_init_queue(); +} + +/** + * + * rct2: 0x0069F06A + */ +static void sub_69F06A() +{ + RCT2_CALLPROC_EBPSAFE(0x0069F06A); return; + + // TODO, bug with the following code + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 0) | (1 << 1) | (1 << 14) | (1 << 2) | (1 << 3); + if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 4))) { + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 4); + banner_init(); // 6B9CB0 + } + if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 6))) { + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 6); + RCT2_CALLPROC_EBPSAFE(0x0069E891); + } + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 7); + if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 8))) { + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 8); + sub_666DFD(); + } + if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 9))) { + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 9); + RCT2_CALLPROC_EBPSAFE(0x0069E89B); + } + if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 13))) { + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 13); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = 127 * 32; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16) = 4350; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = 128; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) = 4095; + } + if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 15))) { + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 15); + RCT2_GLOBAL(0x01358838, uint32) = 0; + } + RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 16) | (1 << 18) | (1 << 19); +} + +/** + * + * rct2: 0x00666DFD + */ +static void sub_666DFD() +{ + int x, y; + rct_map_element *mapElement; + + x = RCT2_GLOBAL(0x013573EA, uint16); + y = RCT2_GLOBAL(0x013573EC, uint16); + if (x == (sint16)0x8000) + return; + + x /= 32; + y /= 32; + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { + if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) { + mapElement->properties.entrance.path_type = 0; + break; + } + } + } while (!map_element_is_last_for_tile(mapElement++)); +} + +#pragma region Tables + +const uint8 RCT1TerrainConvertTable[16] = { + TERRAIN_GRASS, + TERRAIN_SAND, + TERRAIN_DIRT, + TERRAIN_ROCK, + TERRAIN_MARTIAN, + TERRAIN_CHECKERBOARD, + TERRAIN_GRASS_CLUMPS, + TERRAIN_DIRT, // Originally TERRAIN_ROOF_BROWN + TERRAIN_ICE, + TERRAIN_DIRT, // Originally TERRAIN_ROOF_LOG + TERRAIN_DIRT, // Originally TERRAIN_ROOF_IRON + TERRAIN_DIRT, // Originally TERRAIN_ROOF_GREY + TERRAIN_GRID_RED, + TERRAIN_GRID_YELLOW, + TERRAIN_GRID_BLUE, + TERRAIN_GRID_GREEN +}; + +const uint8 RCT1TerrainEdgeConvertTable[16] = { + TERRAIN_EDGE_ROCK, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_BRICK + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_IRON + TERRAIN_EDGE_WOOD_RED, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_GREY + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_YELLOW + TERRAIN_EDGE_WOOD_BLACK, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_RED + TERRAIN_EDGE_ICE, + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_PURPLE + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_GREEN + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_STONE_BROWN + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_STONE_GREY + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_SKYSCRAPER_A + TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_SKYSCRAPER_B + TERRAIN_EDGE_ROCK // Unused +}; + +#pragma endregion + +#pragma region RCT1 Default Objects + +static const rct_object_entry RCT1DefaultObjectsRides[] = { + { 0x00008000, { "PTCT1 " }, 0 }, + { 0x00008000, { "TOGST " }, 0 }, + { 0x00008000, { "ARRSW1 " }, 0 }, + { 0x00008000, { "NEMT " }, 0 }, + { 0x00008000, { "ZLDB " }, 0 }, + { 0x00008000, { "NRL " }, 0 }, + { 0x00008000, { "MONO2 " }, 0 }, + { 0x00008000, { "BATFL " }, 0 }, + { 0x00008000, { "RBOAT " }, 0 }, + { 0x00008000, { "WMOUSE " }, 0 }, + { 0x00008000, { "STEEP1 " }, 0 }, + { 0x00008000, { "SPCAR " }, 0 }, + { 0x00008000, { "SSC1 " }, 0 }, + { 0x00008000, { "BOB1 " }, 0 }, + { 0x00008000, { "OBS1 " }, 0 }, + { 0x00008000, { "SCHT1 " }, 0 }, + { 0x00008000, { "DING1 " }, 0 }, + { 0x00008000, { "AMT1 " }, 0 }, + { 0x00008000, { "CLIFT1 " }, 0 }, + { 0x00008000, { "ARRT1 " }, 0 }, + { 0x00008000, { "HMAZE " }, 0 }, + { 0x00008000, { "HSKELT " }, 0 }, + { 0x00008000, { "KART1 " }, 0 }, + { 0x00008000, { "LFB1 " }, 0 }, + { 0x00008000, { "RAPBOAT " }, 0 }, + { 0x00008000, { "DODG1 " }, 0 }, + { 0x00008000, { "SWSH1 " }, 0 }, + { 0x00008000, { "SWSH2 " }, 0 }, + { 0x00008000, { "ICECR1 " }, 0 }, + { 0x00008000, { "CHPSH2 " }, 0 }, + { 0x00008000, { "DRNKS " }, 0 }, + { 0x00008000, { "CNDYF " }, 0 }, + { 0x00008000, { "BURGB " }, 0 }, + { 0x00008000, { "MGR1 " }, 0 }, + { 0x00008000, { "BALLN " }, 0 }, + { 0x00008000, { "INFOK " }, 0 }, + { 0x00008000, { "TLT1 " }, 0 }, + { 0x00008000, { "FWH1 " }, 0 }, + { 0x00008000, { "SIMPOD " }, 0 }, + { 0x00008000, { "C3D " }, 0 }, + { 0x00008000, { "TOPSP1 " }, 0 }, + { 0x00008000, { "SRINGS " }, 0 }, + { 0x00008000, { "REVF1 " }, 0 }, + { 0x00008000, { "SOUVS " }, 0 }, + { 0x00008000, { "BMVD " }, 0 }, + { 0x00008000, { "PIZZS " }, 0 }, + { 0x00008000, { "TWIST1 " }, 0 }, + { 0x00008000, { "HHBUILD " }, 0 }, + { 0x00008000, { "POPCS " }, 0 }, + { 0x00008000, { "CIRCUS1 " }, 0 }, + { 0x00008000, { "GTC " }, 0 }, + { 0x00008000, { "BMSD " }, 0 }, + { 0x00008000, { "PTCT1 " }, 0 }, + { 0x00008000, { "SFRIC1 " }, 0 }, + { 0x00008000, { "SMC1 " }, 0 }, + { 0x00008000, { "HOTDS " }, 0 }, + { 0x00008000, { "SQDST " }, 0 }, + { 0x00008000, { "HATST " }, 0 }, + { 0x00008000, { "TOFFS " }, 0 }, + { 0x00008000, { "VREEL " }, 0 }, + { 0x00008000, { "SPBOAT " }, 0 }, + { 0x00008000, { "MONBK " }, 0 }, + { 0x00008000, { "BMAIR " }, 0 }, + { 0x00008000, { "SMONO " }, 0 }, + { 0x00000000, { " " }, 0 }, + { 0x00008000, { "REVCAR " }, 0 }, + { 0x00008000, { "UTCAR " }, 0 }, + { 0x00008000, { "GOLF1 " }, 0 }, + { 0x00000000, { " " }, 0 }, + { 0x00008000, { "GDROP1 " }, 0 }, + { 0x00008000, { "FSAUC " }, 0 }, + { 0x00008000, { "CHBUILD " }, 0 }, + { 0x00008000, { "HELICAR " }, 0 }, + { 0x00008000, { "SLCT " }, 0 }, + { 0x00008000, { "CSTBOAT " }, 0 }, + { 0x00008000, { "THCAR " }, 0 }, + { 0x00008000, { "IVMC1 " }, 0 }, + { 0x00008000, { "JSKI " }, 0 }, + { 0x00008000, { "TSHRT " }, 0 }, + { 0x00008000, { "RFTBOAT " }, 0 }, + { 0x00008000, { "DOUGH " }, 0 }, + { 0x00008000, { "ENTERP " }, 0 }, + { 0x00008000, { "COFFS " }, 0 }, + { 0x00008000, { "CHCKS " }, 0 }, + { 0x00008000, { "LEMST " }, 0 } +}; + +// rct2: 0x0098BD0E +static const rct_object_entry RCT1DefaultObjectsSmallScenery[] = { + { 0x00000081, { "TL0 " }, 0 }, + { 0x00000081, { "TL1 " }, 0 }, + { 0x00000081, { "TL2 " }, 0 }, + { 0x00000081, { "TL3 " }, 0 }, + { 0x00000081, { "TM0 " }, 0 }, + { 0x00000081, { "TM1 " }, 0 }, + { 0x00000081, { "TM2 " }, 0 }, + { 0x00000081, { "TM3 " }, 0 }, + { 0x00000081, { "TS0 " }, 0 }, + { 0x00000081, { "TS1 " }, 0 }, + { 0x00000081, { "TS2 " }, 0 }, + { 0x00000081, { "TS3 " }, 0 }, + { 0x00000081, { "TS4 " }, 0 }, + { 0x00000081, { "TS5 " }, 0 }, + { 0x00000081, { "TS6 " }, 0 }, + { 0x00000081, { "TIC " }, 0 }, + { 0x00000081, { "TLC " }, 0 }, + { 0x00000081, { "TMC " }, 0 }, + { 0x00000081, { "TMP " }, 0 }, + { 0x00000081, { "TITC " }, 0 }, + { 0x00000081, { "TGHC " }, 0 }, + { 0x00000081, { "TAC " }, 0 }, + { 0x00000081, { "TGHC2 " }, 0 }, + { 0x00000081, { "TCJ " }, 0 }, + { 0x00000081, { "TMBJ " }, 0 }, + { 0x00000081, { "TCF " }, 0 }, + { 0x00000081, { "TCL " }, 0 }, + { 0x00000081, { "TRF " }, 0 }, + { 0x00000081, { "TRF2 " }, 0 }, + { 0x00000081, { "TEL " }, 0 }, + { 0x00000081, { "TAP " }, 0 }, + { 0x00000081, { "TSP " }, 0 }, + { 0x00000081, { "TMZP " }, 0 }, + { 0x00000081, { "TCRP " }, 0 }, + { 0x00000081, { "TBP " }, 0 }, + { 0x00000081, { "TLP " }, 0 }, + { 0x00000081, { "TWP " }, 0 }, + { 0x00000081, { "TAS " }, 0 }, + { 0x00000081, { "TMG " }, 0 }, + { 0x00000081, { "TWW " }, 0 }, + { 0x00000081, { "TSB " }, 0 }, + { 0x00000081, { "TVL " }, 0 }, + { 0x00000081, { "TCT " }, 0 }, + { 0x00000081, { "TEF " }, 0 }, + { 0x00000081, { "TAL " }, 0 }, + { 0x00000081, { "TSQ " }, 0 }, + { 0x00000081, { "THT " }, 0 }, + { 0x00000081, { "TCB " }, 0 }, + { 0x00000081, { "TDM " }, 0 }, + { 0x00000081, { "TSD " }, 0 }, + { 0x00000081, { "TGS " }, 0 }, + { 0x00000081, { "TUS " }, 0 }, + { 0x00000081, { "TH1 " }, 0 }, + { 0x00000081, { "TBC " }, 0 }, + { 0x00000081, { "TH2 " }, 0 }, + { 0x00000081, { "TPM " }, 0 }, + { 0x00000081, { "TSC " }, 0 }, + { 0x00000081, { "TG1 " }, 0 }, + { 0x00000081, { "TWF " }, 0 }, + { 0x00000081, { "TSH0 " }, 0 }, + { 0x00000081, { "TSH1 " }, 0 }, + { 0x00000081, { "TSH2 " }, 0 }, + { 0x00000081, { "TSH3 " }, 0 }, + { 0x00000081, { "TSH4 " }, 0 }, + { 0x00000081, { "TSH5 " }, 0 }, + { 0x00000081, { "TG2 " }, 0 }, + { 0x00000081, { "TG3 " }, 0 }, + { 0x00000081, { "TG4 " }, 0 }, + { 0x00000081, { "TG5 " }, 0 }, + { 0x00000081, { "TG6 " }, 0 }, + { 0x00000081, { "TG7 " }, 0 }, + { 0x00000081, { "TG8 " }, 0 }, + { 0x00000081, { "TG9 " }, 0 }, + { 0x00000081, { "TG10 " }, 0 }, + { 0x00000081, { "TG11 " }, 0 }, + { 0x00000081, { "TG12 " }, 0 }, + { 0x00000081, { "TG13 " }, 0 }, + { 0x00000081, { "TG14 " }, 0 }, + { 0x00000081, { "TT1 " }, 0 }, + { 0x00000081, { "TDF " }, 0 }, + { 0x00000081, { "TSH " }, 0 }, + { 0x00000081, { "THRS " }, 0 }, + { 0x00000081, { "TSTD " }, 0 }, + { 0x00000081, { "TRMS " }, 0 }, + { 0x00000081, { "TRWS " }, 0 }, + { 0x00000081, { "TRC " }, 0 }, + { 0x00000081, { "TQF " }, 0 }, + { 0x00000081, { "TES1 " }, 0 }, + { 0x00000081, { "TEN " }, 0 }, + { 0x00000081, { "TERS " }, 0 }, + { 0x00000081, { "TERB " }, 0 }, + { 0x00000081, { "TEP " }, 0 }, + { 0x00000081, { "TST1 " }, 0 }, + { 0x00000081, { "TST2 " }, 0 }, + { 0x00000081, { "TMS1 " }, 0 }, + { 0x00000081, { "TAS1 " }, 0 }, + { 0x00000081, { "TAS2 " }, 0 }, + { 0x00000081, { "TAS3 " }, 0 }, + { 0x00000081, { "TST3 " }, 0 }, + { 0x00000081, { "TST4 " }, 0 }, + { 0x00000081, { "TST5 " }, 0 }, + { 0x00000081, { "TAS4 " }, 0 }, + { 0x00000081, { "TCY " }, 0 }, + { 0x00000081, { "TBW " }, 0 }, + { 0x00000081, { "TBR1 " }, 0 }, + { 0x00000081, { "TBR2 " }, 0 }, + { 0x00000081, { "TML " }, 0 }, + { 0x00000081, { "TMW " }, 0 }, + { 0x00000081, { "TBR3 " }, 0 }, + { 0x00000081, { "TBR4 " }, 0 }, + { 0x00000081, { "TMJ " }, 0 }, + { 0x00000081, { "TBR " }, 0 }, + { 0x00000081, { "TMO1 " }, 0 }, + { 0x00000081, { "TMO2 " }, 0 }, + { 0x00000081, { "TMO3 " }, 0 }, + { 0x00000081, { "TMO4 " }, 0 }, + { 0x00000081, { "TMO5 " }, 0 }, + { 0x00000081, { "TWH1 " }, 0 }, + { 0x00000081, { "TWH2 " }, 0 }, + { 0x00000081, { "TNS " }, 0 }, + { 0x00000081, { "TP1 " }, 0 }, + { 0x00000081, { "TP2 " }, 0 }, + { 0x00000081, { "TK1 " }, 0 }, + { 0x00000081, { "TK2 " }, 0 }, + { 0x00000081, { "TR1 " }, 0 }, + { 0x00000081, { "TR2 " }, 0 }, + { 0x00000081, { "TQ1 " }, 0 }, + { 0x00000081, { "TQ2 " }, 0 }, + { 0x00000081, { "TWN " }, 0 }, + { 0x00000081, { "TCE " }, 0 }, + { 0x00000081, { "TCO " }, 0 }, + { 0x00000081, { "THL " }, 0 }, + { 0x00000081, { "TCC " }, 0 }, + { 0x00000081, { "TB1 " }, 0 }, + { 0x00000081, { "TB2 " }, 0 }, + { 0x00000081, { "TK3 " }, 0 }, + { 0x00000081, { "TK4 " }, 0 }, + { 0x00000081, { "TBN " }, 0 }, + { 0x00000081, { "TBN1 " }, 0 }, + { 0x00000081, { "TDT1 " }, 0 }, + { 0x00000081, { "TDT2 " }, 0 }, + { 0x00000081, { "TDT3 " }, 0 }, + { 0x00000081, { "TMM1 " }, 0 }, + { 0x00000081, { "TMM2 " }, 0 }, + { 0x00000081, { "TMM3 " }, 0 }, + { 0x00000081, { "TGS1 " }, 0 }, + { 0x00000081, { "TGS2 " }, 0 }, + { 0x00000081, { "TGS3 " }, 0 }, + { 0x00000081, { "TGS4 " }, 0 }, + { 0x00000081, { "TDN4 " }, 0 }, + { 0x00000081, { "TDN5 " }, 0 }, + { 0x00000081, { "TJT1 " }, 0 }, + { 0x00000081, { "TJT2 " }, 0 }, + { 0x00000081, { "TJB1 " }, 0 }, + { 0x00000081, { "TTF " }, 0 }, + { 0x00000081, { "TF1 " }, 0 }, + { 0x00000081, { "TF2 " }, 0 }, + { 0x00000081, { "TGE1 " }, 0 }, + { 0x00000081, { "TJT3 " }, 0 }, + { 0x00000081, { "TJT4 " }, 0 }, + { 0x00000081, { "TJP1 " }, 0 }, + { 0x00000081, { "TJB2 " }, 0 }, + { 0x00000081, { "TGE2 " }, 0 }, + { 0x00000081, { "TJT5 " }, 0 }, + { 0x00000081, { "TJB3 " }, 0 }, + { 0x00000081, { "TJB4 " }, 0 }, + { 0x00000081, { "TJT6 " }, 0 }, + { 0x00000081, { "TJP2 " }, 0 }, + { 0x00000081, { "TGE3 " }, 0 }, + { 0x00000081, { "TCK " }, 0 }, + { 0x00000081, { "TGE4 " }, 0 }, + { 0x00000081, { "TGE5 " }, 0 }, + { 0x00000081, { "TG15 " }, 0 }, + { 0x00000081, { "TG16 " }, 0 }, + { 0x00000081, { "TG17 " }, 0 }, + { 0x00000081, { "TG18 " }, 0 }, + { 0x00000081, { "TG19 " }, 0 }, + { 0x00000081, { "TG20 " }, 0 }, + { 0x00000081, { "TG21 " }, 0 }, + { 0x00000081, { "TSM " }, 0 }, + { 0x00000081, { "TIG " }, 0 }, + { 0x00000081, { "TCFS " }, 0 }, + { 0x00000081, { "TRFS " }, 0 }, + { 0x00000081, { "TRF3 " }, 0 }, + { 0x00000081, { "TNSS " }, 0 }, + { 0x00000081, { "TCT1 " }, 0 }, + { 0x00000081, { "TCT2 " }, 0 }, + { 0x00000081, { "TSF1 " }, 0 }, + { 0x00000081, { "TSF2 " }, 0 }, + { 0x00000081, { "TSF3 " }, 0 }, + { 0x00000081, { "TCN " }, 0 }, + { 0x00000081, { "TTG " }, 0 }, + { 0x00000081, { "TSNC " }, 0 }, + { 0x00000081, { "TSNB " }, 0 }, + { 0x00000081, { "TSCP " }, 0 }, + { 0x00000081, { "TCD " }, 0 }, + { 0x00000081, { "TSG " }, 0 }, + { 0x00000081, { "TSK " }, 0 }, + { 0x00000081, { "TGH1 " }, 0 }, + { 0x00000081, { "TGH2 " }, 0 }, + { 0x00000081, { "TSMP " }, 0 }, + { 0x00000081, { "TJF " }, 0 }, + { 0x00000081, { "TLY " }, 0 }, + { 0x00000081, { "TGC1 " }, 0 }, + { 0x00000081, { "TGC2 " }, 0 }, + { 0x00000081, { "TGG " }, 0 }, + { 0x00000081, { "TSPH " }, 0 }, + { 0x00000081, { "TOH1 " }, 0 }, + { 0x00000081, { "TOH2 " }, 0 }, + { 0x00000081, { "TOT1 " }, 0 }, + { 0x00000081, { "TOT2 " }, 0 }, + { 0x00000081, { "TOS " }, 0 }, + { 0x00000081, { "TOT3 " }, 0 }, + { 0x00000081, { "TOT4 " }, 0 }, + { 0x00000081, { "TSC2 " }, 0 }, + { 0x00000081, { "TSP1 " }, 0 }, + { 0x00000081, { "TOH3 " }, 0 }, + { 0x00000081, { "TSP2 " }, 0 }, + { 0x00000081, { "ROMROOF1" }, 0 }, + { 0x00000081, { "GEOROOF1" }, 0 }, + { 0x00000081, { "TNTROOF1" }, 0 }, + { 0x00000081, { "JNGROOF1" }, 0 }, + { 0x00000081, { "MINROOF1" }, 0 }, + { 0x00000081, { "ROMROOF2" }, 0 }, + { 0x00000081, { "GEOROOF2" }, 0 }, + { 0x00000081, { "PAGROOF1" }, 0 }, + { 0x00000081, { "SPCROOF1" }, 0 }, + { 0x00000081, { "ROOF1 " }, 0 }, + { 0x00000081, { "ROOF2 " }, 0 }, + { 0x00000081, { "ROOF3 " }, 0 }, + { 0x00000081, { "ROOF4 " }, 0 }, + { 0x00000081, { "ROOF5 " }, 0 }, + { 0x00000081, { "ROOF6 " }, 0 }, + { 0x00000081, { "ROOF7 " }, 0 }, + { 0x00000081, { "ROOF8 " }, 0 }, + { 0x00000081, { "ROOF9 " }, 0 }, + { 0x00000081, { "ROOF10 " }, 0 }, + { 0x00000081, { "ROOF11 " }, 0 }, + { 0x00000081, { "ROOF12 " }, 0 }, + { 0x00000081, { "ROOF13 " }, 0 }, + { 0x00000081, { "ROOF14 " }, 0 }, + { 0x00000081, { "IGROOF " }, 0 }, + { 0x00000081, { "CORROOF " }, 0 }, + { 0x00000081, { "CORROOF2" }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsLargeScenery[] = { + { 0x00000082, { "SCOL " }, 0 }, + { 0x00000082, { "SHS1 " }, 0 }, + { 0x00000082, { "SSPX " }, 0 }, + { 0x00000082, { "SHS2 " }, 0 }, + { 0x00000082, { "SCLN " }, 0 }, + { 0x00000082, { "SMH1 " }, 0 }, + { 0x00000082, { "SMH2 " }, 0 }, + { 0x00000082, { "SVLC " }, 0 }, + { 0x00000082, { "SPYR " }, 0 }, + { 0x00000082, { "SMN1 " }, 0 }, + { 0x00000082, { "SMB " }, 0 }, + { 0x00000082, { "SSK1 " }, 0 }, + { 0x00000082, { "SDN1 " }, 0 }, + { 0x00000082, { "SDN2 " }, 0 }, + { 0x00000082, { "SDN3 " }, 0 }, + { 0x00000082, { "SIP " }, 0 }, + { 0x00000082, { "STB1 " }, 0 }, + { 0x00000082, { "STB2 " }, 0 }, + { 0x00000082, { "STG1 " }, 0 }, + { 0x00000082, { "STG2 " }, 0 }, + { 0x00000082, { "SCT " }, 0 }, + { 0x00000082, { "SOH1 " }, 0 }, + { 0x00000082, { "SOH2 " }, 0 }, + { 0x00000082, { "SOH3 " }, 0 }, + { 0x00000082, { "SGP " }, 0 }, + { 0x00000082, { "SSR " }, 0 }, + { 0x00000082, { "STH " }, 0 }, + { 0x00000082, { "SAH " }, 0 }, + { 0x00000082, { "SPS " }, 0 }, + { 0x00000082, { "SPG " }, 0 }, + { 0x00000082, { "SOB " }, 0 }, + { 0x00000082, { "SAH2 " }, 0 }, + { 0x00000082, { "SST " }, 0 }, + { 0x00000082, { "SSH " }, 0 }, + { 0x00000082, { "SAH3 " }, 0 }, + { 0x00000082, { "SSIG1 " }, 0 }, + { 0x00000082, { "SSIG2 " }, 0 }, + { 0x00000082, { "SSIG3 " }, 0 }, + { 0x00000082, { "SSIG4 " }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsWall[] = { + { 0x00000083, { "WMF " }, 0 }, + { 0x00000083, { "WMFG " }, 0 }, + { 0x00000083, { "WRW " }, 0 }, + { 0x00000083, { "WEW " }, 0 }, + { 0x00000083, { "WHG " }, 0 }, + { 0x00000083, { "WHGG " }, 0 }, + { 0x00000083, { "WCW1 " }, 0 }, + { 0x00000083, { "WCW2 " }, 0 }, + { 0x00000083, { "WSW " }, 0 }, + { 0x00000083, { "WSWG " }, 0 }, + { 0x00000083, { "WMW " }, 0 }, + { 0x00000083, { "WFW1 " }, 0 }, + { 0x00000083, { "WFWG " }, 0 }, + { 0x00000083, { "WPW1 " }, 0 }, + { 0x00000083, { "WPW2 " }, 0 }, + { 0x00000083, { "WPF " }, 0 }, + { 0x00000083, { "WPFG " }, 0 }, + { 0x00000083, { "WWTW " }, 0 }, + { 0x00000083, { "WMWW " }, 0 }, + { 0x00000083, { "WSW1 " }, 0 }, + { 0x00000083, { "WSW2 " }, 0 }, + { 0x00000083, { "WGW2 " }, 0 }, + { 0x00000083, { "WBW " }, 0 }, + { 0x00000083, { "WBR1 " }, 0 }, + { 0x00000083, { "WBRG " }, 0 }, + { 0x00000083, { "WBR2 " }, 0 }, + { 0x00000083, { "WBR3 " }, 0 }, + { 0x00000083, { "WPW3 " }, 0 }, + { 0x00000083, { "WJF " }, 0 }, + { 0x00000083, { "WCH " }, 0 }, + { 0x00000083, { "WCHG " }, 0 }, + { 0x00000083, { "WC1 " }, 0 }, + { 0x00000083, { "WC2 " }, 0 }, + { 0x00000083, { "WC3 " }, 0 }, + { 0x00000083, { "WC4 " }, 0 }, + { 0x00000083, { "WC5 " }, 0 }, + { 0x00000083, { "WC6 " }, 0 }, + { 0x00000083, { "WC7 " }, 0 }, + { 0x00000083, { "WC8 " }, 0 }, + { 0x00000083, { "WC9 " }, 0 }, + { 0x00000083, { "WC10 " }, 0 }, + { 0x00000083, { "WC11 " }, 0 }, + { 0x00000083, { "WC12 " }, 0 }, + { 0x00000083, { "WC13 " }, 0 }, + { 0x00000083, { "WC14 " }, 0 }, + { 0x00000083, { "WC15 " }, 0 }, + { 0x00000083, { "WC16 " }, 0 }, + { 0x00000083, { "WC17 " }, 0 }, + { 0x00000083, { "WC18 " }, 0 }, + { 0x00000083, { "WALLBRDR" }, 0 }, + { 0x00000083, { "WALLBR32" }, 0 }, + { 0x00000083, { "WALLBR16" }, 0 }, + { 0x00000083, { "WALLBR8 " }, 0 }, + { 0x00000083, { "WALLCF8 " }, 0 }, + { 0x00000083, { "WALLCF16" }, 0 }, + { 0x00000083, { "WALLCF32" }, 0 }, + { 0x00000083, { "WALLBB8 " }, 0 }, + { 0x00000083, { "WALLBB16" }, 0 }, + { 0x00000083, { "WALLBB32" }, 0 }, + { 0x00000083, { "WALLRS8 " }, 0 }, + { 0x00000083, { "WALLRS16" }, 0 }, + { 0x00000083, { "WALLRS32" }, 0 }, + { 0x00000083, { "WALLCB8 " }, 0 }, + { 0x00000083, { "WALLCB16" }, 0 }, + { 0x00000083, { "WALLCB32" }, 0 }, + { 0x00000083, { "WALLGL8 " }, 0 }, + { 0x00000083, { "WALLGL16" }, 0 }, + { 0x00000083, { "WALLGL32" }, 0 }, + { 0x00000083, { "WALLWD8 " }, 0 }, + { 0x00000083, { "WALLWD16" }, 0 }, + { 0x00000083, { "WALLWD32" }, 0 }, + { 0x00000083, { "WALLTN32" }, 0 }, + { 0x00000083, { "WALLJN32" }, 0 }, + { 0x00000083, { "WALLMN32" }, 0 }, + { 0x00000083, { "WALLSP32" }, 0 }, + { 0x00000083, { "WALLPG32" }, 0 }, + { 0x00000083, { "WALLU132" }, 0 }, + { 0x00000083, { "WALLU232" }, 0 }, + { 0x00000083, { "WALLCZ32" }, 0 }, + { 0x00000083, { "WALLCW32" }, 0 }, + { 0x00000083, { "WALLCY32" }, 0 }, + { 0x00000083, { "WALLCX32" }, 0 }, + { 0x00000083, { "WBR1A " }, 0 }, + { 0x00000083, { "WBR2A " }, 0 }, + { 0x00000083, { "WRWA " }, 0 }, + { 0x00000083, { "WWTWA " }, 0 }, + { 0x00000083, { "WALLIG16" }, 0 }, + { 0x00000083, { "WALLIG24" }, 0 }, + { 0x00000083, { "WALLCO16" }, 0 }, + { 0x00000083, { "WALLCFDR" }, 0 }, + { 0x00000083, { "WALLCBDR" }, 0 }, + { 0x00000083, { "WALLBRWN" }, 0 }, + { 0x00000083, { "WALLCFWN" }, 0 }, + { 0x00000083, { "WALLCBWN" }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsBanner[] = { + { 0x00000084, { "BN1 " }, 0 }, + { 0x00000084, { "BN2 " }, 0 }, + { 0x00000084, { "BN3 " }, 0 }, + { 0x00000084, { "BN4 " }, 0 }, + { 0x00000084, { "BN5 " }, 0 }, + { 0x00000084, { "BN6 " }, 0 }, + { 0x00000084, { "BN7 " }, 0 }, + { 0x00000084, { "BN8 " }, 0 }, + { 0x00000084, { "BN9 " }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsPath[] = { + { 0x00000085, { "TARMAC " }, 0 }, + { 0x00000085, { "TARMACB " }, 0 }, + { 0x00000085, { "PATHSPCE" }, 0 }, + { 0x00000085, { "PATHDIRT" }, 0 }, + { 0x00000085, { "ROAD " }, 0 }, + { 0x00000085, { "PATHCRZY" }, 0 }, + { 0x00000085, { "PATHASH " }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsPathBits[] = { + { 0x00000086, { "LAMP1 " }, 0 }, + { 0x00000086, { "LAMP2 " }, 0 }, + { 0x00000086, { "LITTER1 " }, 0 }, + { 0x00000086, { "BENCH1 " }, 0 }, + { 0x00000086, { "JUMPFNT1" }, 0 }, + { 0x00000086, { "LAMP3 " }, 0 }, + { 0x00000086, { "LAMP4 " }, 0 }, + { 0x00000086, { "JUMPSNW1" }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsSceneryGroup[] = { + { 0x00000087, { "SCGTREES" }, 0 }, + { 0x00000087, { "SCGSHRUB" }, 0 }, + { 0x00000087, { "SCGGARDN" }, 0 }, + { 0x00000087, { "SCGPATHX" }, 0 }, + { 0x00000087, { "SCGFENCE" }, 0 }, + { 0x00000087, { "SCGMART " }, 0 }, + { 0x00000087, { "SCGWOND " }, 0 }, + { 0x00000087, { "SCGSNOW " }, 0 }, + { 0x00000087, { "SCGWALLS" }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsParkEntrance[] = { + { 0x00000088, { "PKENT1 " }, 0 } +}; + +static const rct_object_entry RCT1DefaultObjectsWater[] = { + { 0x00000089, { "WTRCYAN " }, 0 }, + { 0x00000089, { "WTRORNG " }, 0 } +}; + +static const RCT1DefaultObjectsGroup RCT1DefaultObjects[10] = { + { NULL, 0 }, + { RCT1DefaultObjectsSmallScenery, countof(RCT1DefaultObjectsSmallScenery) }, + { RCT1DefaultObjectsLargeScenery, countof(RCT1DefaultObjectsLargeScenery) }, + { RCT1DefaultObjectsWall, countof(RCT1DefaultObjectsWall) }, + { RCT1DefaultObjectsBanner, countof(RCT1DefaultObjectsBanner) }, + { RCT1DefaultObjectsPath, countof(RCT1DefaultObjectsPath) }, + { RCT1DefaultObjectsPathBits, countof(RCT1DefaultObjectsPathBits) }, + { RCT1DefaultObjectsSceneryGroup, countof(RCT1DefaultObjectsSceneryGroup) }, + { RCT1DefaultObjectsParkEntrance, countof(RCT1DefaultObjectsParkEntrance) }, + { RCT1DefaultObjectsWater, countof(RCT1DefaultObjectsWater) } +}; + +#pragma endregion \ No newline at end of file diff --git a/src/rct1.h b/src/rct1.h new file mode 100644 index 0000000000..d17fbbb7d8 --- /dev/null +++ b/src/rct1.h @@ -0,0 +1,361 @@ +/***************************************************************************** + * 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 _RCT1_H_ +#define _RCT1_H_ + +#include "management/award.h" +#include "management/news_item.h" +#include "management/research.h" +#include "rct2.h" +#include "ride/ride.h" +#include "world/banner.h" +#include "world/map.h" +#include "world/sprite.h" + +typedef struct { + uint16 x; + uint16 y; + uint16 z; + uint8 direction; +} rct1_entrance; + +/** + * RCT1,AA,LL scenario / saved game structure. + * size: 0x1F850C + */ +typedef struct { + uint16 month; + uint16 day; + uint32 ticks; + uint32 random_a; + uint32 random_b; + rct_map_element map_elements[0xC000]; + uint32 unk_counter; + rct_sprite sprites[5000]; + uint16 next_sprite_index; + uint16 first_vehicle_sprite_index; + uint16 first_peep_sprite_index; + uint16 first_duck_sprite_index; + uint16 first_litter_sprite_index; + uint16 first_oversized_ride_car_sprite_index; + uint16 sprites_available; + uint16 num_vehicle_sprites; + uint16 num_peep_sprites; + uint16 num_duck_sprites; + uint16 num_litter_sprites; + uint16 num_oversized_ride_car_sprites; + uint32 park_name_string_index; + uint32 unk_198830; + money32 cash; + money32 loan; + uint32 park_flags; + money16 park_entrance_fee; + rct1_entrance park_entrance; + uint8 unk_198849; + rct2_peep_spawn peep_spawn[2]; + uint8 unk_198856; + uint8 research_level; + uint32 unk_198858; + uint8 available_rides[32]; + uint8 available_vehicles[32]; + uint32 ride_feature_1[128]; + uint32 ride_feature_2[128]; + uint16 guests_in_park; + uint16 unk_198C9E; + money32 expenditure[14 * 16]; + uint32 guests_in_park_2; + uint8 unk_199024; + uint8 handman_colour; + uint8 mechanic_colour; + uint8 security_guard_colour; + uint8 available_scenery[128]; + uint16 available_banners; + uint8 unk_1990AA[94]; + uint16 park_rating; + uint8 park_rating_history[32]; + uint8 guests_in_park_history[32]; + uint8 research_priority; + uint8 research_progress; + uint8 last_research_item; + uint8 last_research_ride; + uint8 last_research_category; + uint8 last_research_flag; + rct_research_item research_items[200]; + uint8 next_research_item; + uint8 next_research_ride; + uint8 next_research_category; + uint8 next_research_flag; + uint16 unk_19953C; + uint32 unk_19953E; + uint16 cheat_detection_land_owned; + uint16 unk_199544; + money16 median_recommended_park_entry_fee; + money32 max_loan; + money16 guest_initial_cash; + uint8 guest_initial_hunger; + uint8 guest_initial_thirst; + uint8 scenario_objective_type; + uint8 scenario_objective_years; + uint16 unk_199552; + money32 scenario_objective_currency; + uint16 scenario_objective_num_guests; + uint8 marketing_status[20]; + uint8 marketing_assoc[20]; + uint8 unk_199582[2]; + money32 cash_history[128]; + money32 total_expenditure; + money32 profit; + uint8 unk_199788[8]; + money32 weekly_profit_history[128]; + money32 park_value; + money32 park_value_history[128]; + uint32 scenario_objective_score; + uint32 num_admissions; + money32 admission_total_income; + money32 company_value; + uint8 thought_timer[16]; + rct_award awards[4]; + money16 land_price; + money16 construction_rights_price; + uint16 unk_199BCC; + uint16 unk_199BCE; + uint32 unk_199BD0; + char username[64]; + uint32 game_version; + money32 objective_completion_company_value; + uint32 finance_checksum; + uint16 num_rides; + uint16 cheat_detection_neg_num_rides; + uint16 cheat_detection_max_owned_tiles; + uint16 cheat_detection_neg_max_owned_tiles; + uint32 finance_checksum_3; + uint32 scenario_slot_index_checksum; + char scenario_winner[32]; + uint32 finance_checksum_2; + char copyright_notice[40]; + uint16 cheat_detection_sv6_sc4[4]; + uint16 unk_199C84; + uint16 unk_199C86; + uint16 map_size_units; + uint16 map_size_unk_b; + uint16 map_size; + uint16 map_size_max_xy; + uint32 same_price_flags; + uint16 unk_199C94; + uint8 unk_199C96[3]; + uint8 water_colour; + uint16 unk_199C9A; + rct_research_item research_items_LL[180]; + uint8 unk_19A020[5468]; + rct_banner banners[100]; + char string_table[32][1024]; + uint32 game_time_counter; + rct_ride rides[255]; + uint16 unk_game_time_counter; + uint16 view_x; + uint16 view_y; + uint8 view_zoom; + uint8 view_rotation; + uint8 map_animations[6000]; + uint32 num_map_animations; + uint8 unk_1CADBC[12]; + uint16 scrolling_text_step; + uint32 unk_1CADCA; + uint16 unk_1CADCE; + uint8 unk_1CADD0[116]; + rct_ride_measurement ride_measurements[8]; + uint32 next_guest_index; + uint16 game_counter_5; + uint8 patrol_areas[0x3C00]; + uint8 unk_1F42AA[116]; + uint8 unk_1F431E[4]; + uint8 unk_1F4322[8]; + uint8 climate; + uint8 unk_1F432B; + uint16 climate_timer; + uint8 weather; + uint8 target_weather; + uint8 temperature; + uint8 target_temperature; + uint8 thunder_frequency; + uint8 target_thunder_frequency; + uint8 weather_gloom; + uint8 target_weather_gloom; + uint8 rain; + uint8 target_rain; + rct_news_item messages[61]; + char scenario_name[62]; + uint16 scenario_slot_index; + uint32 scenario_flags; + uint8 unk_1F8358[432]; + uint32 expansion_pack_checksum; +} rct1_s4; + +enum { + RCT1_RIDE_TYPE_NULL = 255, + RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER = 0, + RCT1_RIDE_TYPE_STAND_UP_STEEL_ROLLER_COASTER, + RCT1_RIDE_TYPE_SUSPENDED_ROLLER_COASTER, + RCT1_RIDE_TYPE_INVERTED_ROLLER_COASTER, + RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER, + RCT1_RIDE_TYPE_MINIATURE_RAILROAD, + RCT1_RIDE_TYPE_MONORAIL, + RCT1_RIDE_TYPE_SUSPENDED_SINGLE_RAIL_ROLLER_COASTER, + RCT1_RIDE_TYPE_BOAT_HIRE, + RCT1_RIDE_TYPE_WOODEN_CRAZY_RODENT_ROLLER_COASTER, + RCT1_RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER, + RCT1_RIDE_TYPE_CAR_RIDE, + RCT1_RIDE_TYPE_WHOA_BELLY, + RCT1_RIDE_TYPE_BOBSLED_ROLLER_COASTER, + RCT1_RIDE_TYPE_OBSERVATION_TOWER, + RCT1_RIDE_TYPE_STEEL_ROLLER_COASTER, + RCT1_RIDE_TYPE_WATER_SLIDE, + RCT1_RIDE_TYPE_MINE_TRAIN_ROLLER_COASTER, + RCT1_RIDE_TYPE_CHAIRLIFT, + RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER, + RCT1_RIDE_TYPE_HEDGE_MAZE, + RCT1_RIDE_TYPE_SPIRAL_SLIDE, + RCT1_RIDE_TYPE_GO_KARTS, + RCT1_RIDE_TYPE_LOG_FLUME, + RCT1_RIDE_TYPE_RIVER_RAPIDS, + RCT1_RIDE_TYPE_DODGEMS, + RCT1_RIDE_TYPE_SWINGING_SHIP, + RCT1_RIDE_TYPE_SWINGING_INVERTER_SHIP, + RCT1_RIDE_TYPE_ICE_CREAM_STALL, + RCT1_RIDE_TYPE_FRIES_STALL, + RCT1_RIDE_TYPE_DRINK_STALL, + RCT1_RIDE_TYPE_COTTON_CANDY_STALL, + RCT1_RIDE_TYPE_BURGER_BAR, + RCT1_RIDE_TYPE_MERRY_GO_ROUND, + RCT1_RIDE_TYPE_BALLOON_STALL, + RCT1_RIDE_TYPE_INFORMATION_KIOSK, + RCT1_RIDE_TYPE_TOILETS, + RCT1_RIDE_TYPE_FERRIS_WHEEL, + RCT1_RIDE_TYPE_MOTION_SIMULATOR, + RCT1_RIDE_TYPE_3D_CINEMA, + RCT1_RIDE_TYPE_GRAVITRON, + RCT1_RIDE_TYPE_SPACE_RINGS, + RCT1_RIDE_TYPE_REVERSE_WHOA_BELLY_ROLLER_COASTER, + RCT1_RIDE_TYPE_SOUVENIR_STALL, + RCT1_RIDE_TYPE_VERTICAL_ROLLER_COASTER, + RCT1_RIDE_TYPE_PIZZA_STALL, + RCT1_RIDE_TYPE_SCRAMBLED_EGGS, + RCT1_RIDE_TYPE_HAUNTED_HOUSE, + RCT1_RIDE_TYPE_POPCORN_STALL, + RCT1_RIDE_TYPE_CIRCUS_SHOW, + RCT1_RIDE_TYPE_GHOST_TRAIN, + RCT1_RIDE_TYPE_STEEL_TWISTER_ROLLER_COASTER, + RCT1_RIDE_TYPE_WOODEN_TWISTER_ROLLER_COASTER, + RCT1_RIDE_TYPE_WOODEN_SIDE_FRICTION_ROLLER_COASTER, + RCT1_RIDE_TYPE_STEEL_WILD_MOUSE_ROLLER_COASTER, + RCT1_RIDE_TYPE_HOT_DOG_STALL, + RCT1_RIDE_TYPE_EXOTIC_SEA_FOOD_STALL, + RCT1_RIDE_TYPE_HAT_STALL, + RCT1_RIDE_TYPE_CANDY_APPLE_STAND, + RCT1_RIDE_TYPE_VIRGINIA_REEL, + RCT1_RIDE_TYPE_RIVER_RIDE, + RCT1_RIDE_TYPE_CYCLE_MONORAIL, + RCT1_RIDE_TYPE_FLYING_ROLLER_COASTER, + RCT1_RIDE_TYPE_SUSPENDED_MONORAIL, + RCT1_RIDE_TYPE_40, + RCT1_RIDE_TYPE_WOODEN_REVERSER_ROLLER_COASTER, + RCT1_RIDE_TYPE_HEARTLINE_TWISTER_ROLLER_COASTER, + RCT1_RIDE_TYPE_MINIATURE_GOLF, + RCT1_RIDE_TYPE_44, + RCT1_RIDE_TYPE_ROTO_DROP, + RCT1_RIDE_TYPE_FLYING_SAUCERS, + RCT1_RIDE_TYPE_CROOKED_HOUSE, + RCT1_RIDE_TYPE_CYCLE_RAILWAY, + RCT1_RIDE_TYPE_SUSPENDED_LOOPING_ROLLER_COASTER, + RCT1_RIDE_TYPE_WATER_COASTER, + RCT1_RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER, + RCT1_RIDE_TYPE_INVERTED_WILD_MOUSE_COASTER, + RCT1_RIDE_TYPE_JET_SKIS, + RCT1_RIDE_TYPE_T_SHIRT_STALL, + RCT1_RIDE_TYPE_RAFT_RIDE, + RCT1_RIDE_TYPE_DOUGHNUT_SHOP, + RCT1_RIDE_TYPE_ENTERPRISE, + RCT1_RIDE_TYPE_COFFEE_SHOP, + RCT1_RIDE_TYPE_FRIED_CHICKEN_STALL, + RCT1_RIDE_TYPE_LEMONADE_STALL +}; + +enum{ + RCT1_TRACK_ELEM_BOOSTER = 100 +}; + +enum{ + RCT1_RIDE_MODE_POWERED_LAUNCH = 3, + +}; + +typedef struct{ + uint8 type; // 0x00 + uint8 vehicle_type; // 0x01 + uint32 special_track_flags; // 0x02 + uint8 operating_mode; // 0x06 + uint8 vehicle_colour_version; // 0x07 Vehicle colour type in first two bits, Version in bits 3,4 + uint8 body_trim_colour[24]; // 0x08 + uint8 track_spine_colour_rct1; // 0x20 + uint8 track_rail_colour_rct1; // 0x21 + uint8 track_support_colour_rct1; // 0x22 + uint8 departure_control_flags; // 0x23 + uint8 number_of_trains; // 0x24 + uint8 cars_per_train; // 0x25 + uint8 min_wait_time; // 0x26 + uint8 max_wait_time; // 0x27 + uint8 speed; // 0x28 + uint8 max_speed; // 0x29 + uint8 average_speed; // 0x2A + uint16 ride_length; // 0x2B + uint8 max_positive_vertical_g; // 0x2D + uint8 max_negitive_vertical_g; // 0x2E + uint8 max_lateral_g; // 0x2F + union { + uint8 inversions; // 0x30 + uint8 holes; // 0x30 + }; + uint8 drops; // 0x31 + uint8 highest_drop_height; // 0x32 + uint8 excitement; // 0x33 + uint8 intensity; // 0x34 + uint8 nausea; // 0x35 + uint8 pad_36[2]; + union{ + uint16 start_track_data_original; // 0x38 + uint8 track_spine_colour[4]; // 0x38 + }; + uint8 track_rail_colour[4]; // 0x3C + union{ + uint8 track_support_colour[4]; // 0x40 + uint8 wall_type[4]; // 0x40 + }; + uint8 pad_41[0x83]; + uint16 start_track_data_AA_CF; // 0xC4 +}rct_track_td4; // Information based off RCTTechDepot + +bool rct1_read_sc4(const char *path, rct1_s4 *s4); +bool rct1_read_sv4(const char *path, rct1_s4 *s4); +void rct1_import_s4(rct1_s4 *s4); +void rct1_fix_landscape(); + +#endif + \ No newline at end of file diff --git a/src/rct2.c b/src/rct2.c index 916bceb320..b174cfa7e8 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -28,14 +28,15 @@ #include "drawing/drawing.h" #include "editor.h" #include "game.h" +#include "interface/console.h" #include "interface/viewport.h" #include "intro.h" #include "localisation/date.h" #include "localisation/localisation.h" #include "management/news_item.h" +#include "network/twitch.h" #include "object.h" #include "openrct2.h" -#include "platform/osinterface.h" #include "platform/platform.h" #include "ride/ride.h" #include "ride/track.h" @@ -44,6 +45,7 @@ #include "world/map.h" #include "world/park.h" #include "world/climate.h" +#include "world/scenery.h" #include "world/sprite.h" typedef struct tm tm_t; @@ -57,12 +59,10 @@ static void rct2_update_2(); static jmp_buf _end_update_jump; -void rct2_quit() { - if (gGeneral_config.confirmation_prompt) { - RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16) = PM_QUIT; - window_save_prompt_open(); - } else - openrct2_finish(); +void rct2_quit() +{ + RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16) = PM_QUIT; + window_save_prompt_open(); } int rct2_init() @@ -72,8 +72,9 @@ int rct2_init() RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) = 0; RCT2_GLOBAL(0x009AC310, char*) = RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, char*); get_system_time(); + srand((unsigned int)time(0)); RCT2_GLOBAL(0x009DEA69, short) = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAY, short); - RCT2_GLOBAL(0x009DEA6B, short) = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAY, short); + RCT2_GLOBAL(0x009DEA6B, short) = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MONTH, short); if (!rct2_init_directories()) return 0; @@ -81,9 +82,9 @@ int rct2_init() return 0; config_reset_shortcut_keys(); + config_shortcut_keys_load(); RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = 0; // config_load(); - // RCT2_CALLPROC_EBPSAFE(0x00674B81); // pointless expansion pack crap object_list_load(); scenario_load_list(); @@ -92,9 +93,12 @@ int rct2_init() track_load_list(item); gfx_load_g1(); + gfx_load_g2(); gfx_load_character_widths(); - osinterface_init(); - audio_init1();//RCT2_CALLPROC_EBPSAFE(0x006BA8E0); // init_audio(); + if (!gOpenRCT2Headless) { + platform_init(); + audio_init1(); + } viewport_init_all(); news_item_init_queue(); get_local_time(); @@ -103,22 +107,25 @@ int rct2_init() reset_sprite_list(); ride_init_all(); window_guest_list_init_vars_a(); - sub_6BD3A4();// RCT2_CALLPROC_EBPSAFE(0x006BD3A4); //Peep? - map_init(); + sub_6BD3A4(); + map_init(150); park_init(); - RCT2_CALLPROC_EBPSAFE(0x0066B5C0); // 0x0066B5C0 (part of 0x0066B3E8) screen_game_create_windows() + if (!gOpenRCT2Headless) + window_title_menu_open(); date_reset(); climate_reset(CLIMATE_COOL_AND_WET); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); + scenery_set_default_placement_configuration(); window_new_ride_init_vars(); window_guest_list_init_vars_b(); window_staff_list_init_vars(); - title_load(); + if (!gOpenRCT2Headless) { + title_load(); - gfx_clear(RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo), 10); - RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = gGeneral_config.play_intro ? 8 : 255; + gfx_clear(RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo), 10); + } + log_verbose("initialising game finished"); return 1; } @@ -128,16 +135,18 @@ int rct2_init() */ int rct2_init_directories() { + // windows_get_registry_install_info((rct2_install_info*)0x009AA10C, "RollerCoaster Tycoon 2 Setup", "MS Sans Serif", 0); + // check install directory - if (!platform_directory_exists(gGeneral_config.game_path)) { - log_verbose("install directory does not exist, %s", gGeneral_config.game_path); + if (!platform_directory_exists(gConfigGeneral.game_path)) { + log_verbose("install directory does not exist, %s", gConfigGeneral.game_path); if (!config_find_or_browse_install_directory()) { log_fatal("Invalid RCT2 installation path. Please correct in config.ini."); return 0; - } + } } - strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char), gGeneral_config.game_path); + strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char), gConfigGeneral.game_path); strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char)); strcat(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), "\\"); @@ -222,7 +231,10 @@ int rct2_open_file(const char *path) strcpy(scenarioBasic.path, path); scenario_load_and_play_from_path(scenarioBasic.path); } else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) { + return 1; + } else if (!_stricmp(extension, "td6") || !_stricmp(extension, "td4")) { // TODO track design install + return 1; } return 0; @@ -233,10 +245,10 @@ int rct2_open_file(const char *path) * rct2: 0x00674C95 */ int check_file_paths() -{ + { for (int pathId = 0; pathId < PATH_ID_END; pathId++) if (!check_file_path(pathId)) - return 0; + return 0; return 1; } @@ -251,24 +263,7 @@ int check_file_path(int pathId) HANDLE file = CreateFile(path, FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); switch (pathId) { - case PATH_ID_GAMECFG: - case PATH_ID_SCORES: - case PATH_ID_TRACKSIDX: - case PATH_ID_PLUGIN: - // Do nothing; these will be created later if they do not exist yet - break; - - case PATH_ID_CUSTOM1: - if (file != INVALID_HANDLE_VALUE) - RCT2_GLOBAL(0x009AF164, unsigned int) = SetFilePointer(file, 0, 0, FILE_END); // Store file size in music_custom1_size @ 0x009AF164 - break; - - case PATH_ID_CUSTOM2: - if (file != INVALID_HANDLE_VALUE) - RCT2_GLOBAL(0x009AF16E, unsigned int) = SetFilePointer(file, 0, 0, FILE_END); // Store file size in music_custom2_size @ 0x009AF16E - break; - - default: + case PATH_ID_G1: if (file == INVALID_HANDLE_VALUE) { // A data file is missing from the installation directory. The original implementation // asks for a CD-ROM path at this point and stores it in cdrom_path @ 0x9AA318. @@ -281,6 +276,16 @@ int check_file_path(int pathId) return 0; } break; + + case PATH_ID_CUSTOM1: + if (file != INVALID_HANDLE_VALUE) + ride_music_info_list[36]->length = SetFilePointer(file, 0, 0, FILE_END); // Store file size in music_custom1_size @ 0x009AF164 + break; + + case PATH_ID_CUSTOM2: + if (file != INVALID_HANDLE_VALUE) + ride_music_info_list[37]->length = SetFilePointer(file, 0, 0, FILE_END); // Store file size in music_custom2_size @ 0x009AF16E + break; } if (file != INVALID_HANDLE_VALUE) @@ -294,11 +299,11 @@ int check_file_path(int pathId) * rct2: 0x00674C0B */ int check_files_integrity() -{ + { int i; const char *path; HANDLE file; - WIN32_FIND_DATA find_data; + WIN32_FIND_DATA find_data; for (i = 0; files_to_check[i].pathId != PATH_ID_END; i++) { path = get_file_path(files_to_check[i].pathId); @@ -324,16 +329,12 @@ void rct2_update_2() tick = timeGetTime(); - RCT2_GLOBAL(0x009DE588, sint16) = tick2 = tick - RCT2_GLOBAL(0x009DE580, sint32); - if (RCT2_GLOBAL(0x009DE588, sint16) > 500) - RCT2_GLOBAL(0x009DE588, sint16) = 500; + tick2 = tick - RCT2_GLOBAL(0x009DE580, sint32); + RCT2_GLOBAL(0x009DE588, sint16) = tick2 = min(tick2, 500); RCT2_GLOBAL(0x009DE580, sint32) = tick; - if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0) - RCT2_GLOBAL(0x009DE584, sint32) += tick2; - - if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0) - RCT2_GLOBAL(0x009DE584, sint32) += tick2; + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) + RCT2_GLOBAL(RCT2_ADDRESS_PALETTE_EFFECT_FRAME_NO, sint32) += tick2; if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) RCT2_GLOBAL(0x009DE588, sint16) = 31; @@ -348,6 +349,10 @@ void rct2_update_2() title_update(); else game_update(); + + twitch_update(); + console_update(); + console_draw(RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo)); } void rct2_endupdate() @@ -366,14 +371,14 @@ const char *get_file_path(int pathId) // The original implementation checks if the file is on CD-ROM here (file_on_cdrom[pathId] @ 0x009AA0B1). // If so, the CD-ROM path (cdrom_path @ 0x9AA318) is used instead. This has been removed for now for // the sake of simplicity. - strcpy(path, gGeneral_config.game_path); + strcpy(path, gConfigGeneral.game_path); // Make sure base path is terminated with a slash if (strlen(path) == 0 || path[strlen(path) - 1] != '\\') { if (strlen(path) >= MAX_PATH - 1) { - RCT2_ERROR("Path for %s too long", file_paths[pathId]); + log_error("Path for %s too long", file_paths[pathId]); path[0] = '\0'; return path; } @@ -382,9 +387,8 @@ const char *get_file_path(int pathId) } // Concatenate file path - if (strlen(path) + strlen(file_paths[pathId]) > MAX_PATH) - { - RCT2_ERROR("Path for %s too long", file_paths[pathId]); + if (strlen(path) + strlen(file_paths[pathId]) > MAX_PATH) { + log_error("Path for %s too long", file_paths[pathId]); path[0] = '\0'; return path; } @@ -513,4 +517,4 @@ void *rct2_realloc(void *block, size_t numBytes) void rct2_free(void *block) { RCT2_CALLPROC_1(0x004068DE, void*, block); -} \ No newline at end of file +} diff --git a/src/rct2.h b/src/rct2.h index af4c77fe19..0ea6a5665b 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -43,6 +43,12 @@ typedef unsigned short uint16; typedef unsigned long uint32; typedef unsigned long long uint64; +typedef char utf8; +typedef utf8* utf8string; +typedef const utf8* const_utf8string; +typedef wchar_t utf16; +typedef utf16* utf16string; + #define rol8(x, shift) (((uint8)(x) << (shift)) | ((uint8)(x) >> (8 - (shift)))) #define ror8(x, shift) (((uint8)(x) >> (shift)) | ((uint8)(x) << (8 - (shift)))) #define rol16(x, shift) (((uint16)(x) << (shift)) | ((uint16)(x) >> (16 - (shift)))) @@ -62,23 +68,23 @@ typedef unsigned long long uint64; #define countof(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) -#ifdef _MSC_VER -#define RCT2_ERROR(format,...) fprintf(stderr, "ERROR %s:%s():%d: " format "\n", __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); -#else -#define RCT2_ERROR(format,...) fprintf(stderr, "ERROR %s:%s():%d: " format "\n", __FILE__, __func__, __LINE__, ## __VA_ARGS__); -#endif - #ifndef _MSC_VER // use similar struct packing as MSVC for our structs #pragma pack(1) #endif #define OPENRCT2_NAME "OpenRCT2" -#define OPENRCT2_VERSION "0.0.1" +#define OPENRCT2_VERSION "0.0.2" #define OPENRCT2_ARCHITECTURE "x86" #define OPENRCT2_PLATFORM "Windows" #define OPENRCT2_TIMESTAMP __DATE__ " " __TIME__ +// The following constants are for automated build servers +#define OPENRCT2_BUILD_SERVER "" +#define OPENRCT2_BRANCH "" +#define OPENRCT2_COMMIT_SHA1 "" +#define OPENRCT2_COMMIT_SHA1_SHORT "" + // Represent fixed point numbers. dp = decimal point typedef sint16 fixed16_1dp; typedef sint16 fixed16_2dp; @@ -98,12 +104,28 @@ typedef fixed32_1dp money32; // Construct a money value in the format MONEY(10,70) to represent 10.70. Fractional part must be two digits. #define MONEY(whole, fraction) ((whole) * 10 + ((fraction) / 10)) +#define MONEY_FREE MONEY(0,00) #define MONEY32_UNDEFINED ((money32)0x80000000) +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif typedef void (EMPTY_ARGS_VOID_POINTER)(); typedef unsigned short rct_string_id; +typedef struct { + uint32 installLevel; + char title[260]; + char path[260]; + uint32 var_20C; + uint8 pad_210[256]; + char expansionPackNames[16][128]; + uint32 activeExpansionPacks; //0xB10 +} rct2_install_info; + enum { + // Although this is labeled a flag it actually means when + // zero the screen is in playing mode. SCREEN_FLAGS_PLAYING = 0, SCREEN_FLAGS_TITLE_DEMO = 1, SCREEN_FLAGS_SCENARIO_EDITOR = 2, @@ -176,6 +198,7 @@ enum { PATH_ID_CSS44, PATH_ID_CSS45, PATH_ID_CSS46, + PATH_ID_CSS50, PATH_ID_END }; @@ -243,7 +266,8 @@ static const char * const file_paths[] = "Data\\CSS43.DAT", "Data\\CSS44.DAT", "Data\\CSS45.DAT", - "Data\\CSS46.DAT" + "Data\\CSS46.DAT", + "Data\\CSS50.DAT" }; // Files to check (rct2 @ 0x0097FB5A) diff --git a/src/ride/ride.c b/src/ride/ride.c index b685915043..519fd72bd4 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -21,22 +21,27 @@ #include "../addresses.h" #include "../audio/audio.h" #include "../audio/mixer.h" +#include "../common.h" +#include "../config.h" #include "../game.h" #include "../input.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 "../peep/peep.h" #include "../peep/staff.h" -#include "../platform/osinterface.h" #include "../scenario.h" #include "../util/util.h" #include "../windows/error.h" +#include "../world/banner.h" #include "../world/map.h" #include "../world/sprite.h" #include "ride.h" #include "ride_data.h" +#include "track.h" #include "station.h" #pragma region Ride classification table @@ -129,7 +134,7 @@ static int ride_get_new_breakdown_problem(rct_ride *ride); static void ride_inspection_update(rct_ride *ride); static void ride_mechanic_status_update(int rideIndex, int mechanicStatus); static void ride_music_update(int rideIndex); -static void ride_prepare_breakdown(int rideIndex, int breakdownReason); +void ride_prepare_breakdown(int rideIndex, int breakdownReason); static void ride_shop_connected(rct_ride* ride, int ride_idx); static void ride_spiral_slide_update(rct_ride *ride); static void ride_update(int rideIndex); @@ -139,6 +144,15 @@ rct_ride_type *ride_get_entry(rct_ride *ride) return GET_RIDE_ENTRY(ride->subtype); } +/** +* +* rct2: 0x006DED68 +*/ +void reset_type_to_ride_entry_index_map(){ + uint8* typeToRideEntryIndexMap = RCT2_ADDRESS(0x009E32F8, uint8); + memset(typeToRideEntryIndexMap, 0xFF, 91); +} + uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType) { uint8 *typeToRideEntryIndexMap = (uint8*)0x009E32F8; @@ -200,7 +214,7 @@ void ride_update_favourited_stat() if (peep->favourite_ride != 0xff) { ride = &g_ride_list[peep->favourite_ride]; ride->guests_favourite++; - ride->var_14D |= 1; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; } @@ -247,6 +261,7 @@ money32 ride_calculate_income_per_hour(rct_ride *ride) shopItem = entry->shop_item_secondary; if (shopItem != 255) { + priceMinusCost += ride->price_secondary; priceMinusCost -= get_shop_item_cost(shopItem); priceMinusCost /= 2; } @@ -264,74 +279,117 @@ money32 ride_calculate_income_per_hour(rct_ride *ride) * dl ride index * esi result map element */ -rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY) +int sub_6CAF80(int rideIndex, rct_xy_element *output) { - rct_map_element *resultMapElement, *mapElement; + map_element_iterator it; + rct_map_element *resultMapElement; int foundSpecialTrackPiece; - resultMapElement = (rct_map_element*)-1; + resultMapElement = NULL; foundSpecialTrackPiece = 0; - uint16 x, y; - for (x = 0; x < 256; x++) { - for (y = 0; y < 256; y++) { - // Iterate through map elements on tile - int tileIndex = (y << 8) | x; - mapElement = TILE_MAP_ELEMENT_POINTER(tileIndex); - do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_TRACK) - continue; - if (rideIndex != mapElement->properties.track.ride_index) - continue; + map_element_iterator_begin(&it); + do { + if (map_element_get_type(it.element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (rideIndex != it.element->properties.track.ride_index) + continue; - // Found a track piece for target ride + // Found a track piece for target ride - // Check if its a ??? - int specialTrackPiece = ( - (mapElement->properties.track.type != 2 && mapElement->properties.track.type != 3) && - (RCT2_ADDRESS(0x0099BA64, uint8)[mapElement->properties.track.type * 16] & 0x10) - ); + // Check if its not the station or ??? (but allow end piece of station) + int specialTrackPiece = ( + it.element->properties.track.type != 2 && + it.element->properties.track.type != 3 && + (RCT2_ADDRESS(0x0099BA64, uint8)[it.element->properties.track.type * 16] & 0x10) + ); - // Set result tile to this track piece if first found track or a ??? - if (resultMapElement == (rct_map_element*)-1 || specialTrackPiece) { - resultMapElement = mapElement; + // Set result tile to this track piece if first found track or a ??? + if (resultMapElement == NULL || specialTrackPiece) { + resultMapElement = it.element; - if (outX != NULL) *outX = x * 32; - if (outY != NULL) *outY = y * 32; - } - - if (specialTrackPiece) { - foundSpecialTrackPiece = 1; - return resultMapElement; - } - } while (!(mapElement->flags & MAP_ELEMENT_FLAG_LAST_TILE) && mapElement++); + if (output != NULL) { + output->element = resultMapElement; + output->x = it.x * 32; + output->y = it.y * 32; + } } - } - return resultMapElement; + + if (specialTrackPiece) { + foundSpecialTrackPiece = 1; + return 1; + } + } while (map_element_iterator_next(&it)); + + return resultMapElement != NULL; } /** * + * rct2: 0x006C60C2 + */ +int track_get_next(rct_xy_element *input, rct_xy_element *output) +{ + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006C60C2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = *((uint16*)&eax); + output->y = *((uint16*)&ecx); + output->element = (rct_map_element*)esi; + + return (result & 0x100) == 0; +} + +/** + * + * Make sure to pass in the x and y of the start track element too. * rct2: 0x006CB02F * ax result x * bx result y * esi input / output map element */ -rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *outX, int *outY) +int ride_find_track_gap(rct_xy_element *input, rct_xy_element *output) { - int eax, ebx, ecx, edx, esi, edi, ebp; - esi = (int)startTrackElement; - eax = *outX; - ebx = 0; - ecx = *outY; - edx = 0; - edi = 0; - ebp = 0; - RCT2_CALLFUNC_X(0x006CB02F, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + int rideIndex; + rct_xy_element trackElement, nextTrackElement; + rct_map_element *loopTrackElement; + rct_ride *ride; + rct_window *w; - if (outX != NULL) *outX = eax & 0xFFFF; - if (outY != NULL) *outY = ecx & 0xFFFF; - return (rct_map_element*)esi; + trackElement = *input; + rideIndex = trackElement.element->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + + if (ride->type == RIDE_TYPE_MAZE) + return 0; + + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && RCT2_GLOBAL(0x00F440A6, uint8) != 0 && RCT2_GLOBAL(0x00F440A7, uint8) == rideIndex) + sub_6C9627(); + + loopTrackElement = NULL; + while (1) { + if (!track_get_next(&trackElement, &nextTrackElement)) { + *output = trackElement; + return 1; + } + + if (!track_is_connected_by_shape(trackElement.element, nextTrackElement.element)) { + *output = nextTrackElement; + return 1; + } + + trackElement = nextTrackElement; + if (loopTrackElement == NULL) + loopTrackElement = trackElement.element; + else if (loopTrackElement == trackElement.element) + break; + } + + return 0; } /** @@ -368,7 +426,7 @@ void ride_get_status(int rideIndex, int *formatSecondary, int *argument) *formatSecondary = STR_RACE_WON_BY; } } else { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x20000)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) { *argument = ride->num_riders; *formatSecondary = STR_PERSON_ON_RIDE; if(*argument != 1) @@ -388,6 +446,14 @@ int ride_get_total_length(rct_ride *ride) return totalLength; } +int ride_get_total_time(rct_ride *ride) +{ + int i, totalTime = 0; + for (i = 0; i < ride->num_stations; i++) + totalTime += ride->time[i]; + return totalTime; +} + int ride_can_have_multiple_circuits(rct_ride *ride) { if (!(RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x200)) @@ -397,7 +463,7 @@ int ride_can_have_multiple_circuits(rct_ride *ride) if ( ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT && ride->mode != RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE && - ride->mode != RIDE_MODE_POWERED_LAUNCH + ride->mode != RIDE_MODE_POWERED_LAUNCH_PASSTROUGH ) { return 0; } @@ -481,7 +547,7 @@ static rct_window *ride_create_or_find_construction_window(int rideIndex) RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; w = window_construction_open(rideIndex); } else { - RCT2_CALLPROC_X(0x006C9627, 0, 0, 0, 0, 0, 0, 0); + sub_6C9627(); RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; } @@ -502,7 +568,7 @@ int ride_create_ride(ride_list_item listItem) esi = GAME_COMMAND_6; game_do_command_p(esi, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return ebx == 0x80000000 ? -1 : edi; + return ebx == MONEY32_UNDEFINED ? -1 : edi; } /** @@ -511,20 +577,31 @@ int ride_create_ride(ride_list_item listItem) */ void ride_construct_new(ride_list_item listItem) { - rct_window *w; int rideIndex; rideIndex = ride_create_ride(listItem); - if (rideIndex == -1) - return; + if (rideIndex != -1) + ride_construct(rideIndex); +} - // Open construction window - // HACK In the original game this created a mouse up event. This has been - // replaced with a direct call to the function that gets called. - // Eventually should be changed so the ride window does not need to be opened. - w = window_ride_main_open(rideIndex); - window_ride_construct(w); - window_close_by_number(WC_RIDE, rideIndex); +/** + * + * rct2: 0x006B4857 + */ +void ride_construct(int rideIndex) +{ + rct_xy_element trackElement; + rct_window *w; + + if (sub_6CAF80(rideIndex, &trackElement)) { + ride_find_track_gap(&trackElement, &trackElement); + + w = window_get_main(); + if (w != NULL && ride_modify(&trackElement)) + window_scroll_to_location(w, trackElement.x, trackElement.y, trackElement.element->base_height * 8); + } else { + sub_6CC3FB(rideIndex); + } } /** @@ -551,7 +628,7 @@ static void ride_remove_cable_lift(rct_ride *ride) do { vehicle = &(g_sprite_list[spriteIndex].vehicle); invalidate_sprite((rct_sprite*)vehicle); - RCT2_CALLPROC_X(0x0069EDB6, 0, 0, 0, 0, (int)vehicle, 0, 0); + sprite_remove((rct_sprite*)vehicle); spriteIndex = vehicle->next_vehicle_on_train; } while (spriteIndex != SPRITE_INDEX_NULL); } @@ -576,7 +653,7 @@ static void ride_remove_vehicles(rct_ride *ride) while (spriteIndex != SPRITE_INDEX_NULL) { vehicle = &(g_sprite_list[spriteIndex].vehicle); invalidate_sprite((rct_sprite*)vehicle); - RCT2_CALLPROC_X(0x0069EDB6, 0, 0, 0, 0, (int)vehicle, 0, 0); + sprite_remove((rct_sprite*)vehicle); spriteIndex = vehicle->next_vehicle_on_train; } @@ -602,7 +679,7 @@ static void ride_clear_for_construction(int rideIndex) ride_measurement_clear(ride); ride->lifecycle_flags &= ~(RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN); - ride->var_14D |= 0x0C; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; ride_remove_cable_lift(ride); ride_remove_vehicles(ride); @@ -669,19 +746,19 @@ static void ride_remove_peeps(int rideIndex) continue; peep_decrement_num_riders(peep); - if (peep->state == PEEP_STATE_QUEUING_FRONT && peep->var_2C == 0) - RCT2_CALLPROC_X(0x006966A9, 0, 0, 0, 0, (int)peep, 0, 0); + if (peep->state == PEEP_STATE_QUEUING_FRONT && peep->sub_state == 0) + remove_peep_from_queue(peep); invalidate_sprite((rct_sprite*)peep); if (exitDirection == 255) { x = peep->next_x + 16; y = peep->next_y + 16; - z = (peep->next_z & 0xFF) * 8; - if ((peep->next_z >> 8) & 4) + z = peep->next_z * 8; + if (peep->next_var_29 & 4) z += 8; z++; - sprite_move(exitX, exitY, exitZ, (rct_sprite*)peep); + sprite_move(x, y, z, (rct_sprite*)peep); } else { sprite_move(exitX, exitY, exitZ, (rct_sprite*)peep); peep->sprite_direction = exitDirection; @@ -699,12 +776,173 @@ static void ride_remove_peeps(int rideIndex) ride->num_riders = 0; ride->var_15D = 0; - ride->var_14D |= 4; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN; } -void sub_6C683D(int x, int y, int z, int direction, int type, int esi, int edi, int ebp) +/* rct2: 0x006C683D + * ax : x + * bx : direction << 8, type + * cx : y + * dx : z + * si : extra_params + * di : output_element + * bp : flags + */ +int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element** output_element, uint16 flags) { - RCT2_CALLPROC_X(0x006C683D, x, (direction << 8) | type, y, z, esi, edi, ebp); + rct_map_element* map_element = map_get_first_element_at(*x / 32, *y / 32); + rct_map_element* success_map = NULL; + + do{ + if (map_element->base_height != *z / 8) + continue; + + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + continue; + + if (type != map_element->properties.track.type) + continue; + + success_map = map_element; + if (!(map_element->properties.track.sequence & 0xF)) + break; + }while(!map_element_is_last_for_tile(map_element++)); + + map_element = success_map; + + if (map_element == NULL){ + return 1; + } + + // Possibly z should be &0xF8 + rct_ride* ride = GET_RIDE(map_element->properties.track.ride_index); + rct_preview_track *trackBlock; + + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_SELLS_FOOD){ + trackBlock = RCT2_ADDRESS(0x00994A38, rct_preview_track*)[type]; + } + else{ + trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[type]; + } + + int sequence = map_element->properties.track.sequence & 0xF; + + uint8 map_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + switch (map_direction){ + case MAP_ELEMENT_DIRECTION_WEST: + *x -= trackBlock[sequence].x; + *y -= trackBlock[sequence].y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + *x -= trackBlock[sequence].y; + *y += trackBlock[sequence].x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + *x += trackBlock[sequence].x; + *y += trackBlock[sequence].y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + *x += trackBlock[sequence].y; + *y -= trackBlock[sequence].x; + break; + } + + *z -= trackBlock[sequence].z; + + int start_x = *x, start_y = *y, start_z = *z; + + *z += trackBlock[0].z; + + for (int i = 0; trackBlock[i].var_00 != 0xFF; ++i){ + int cur_x = start_x, cur_y = start_y, cur_z = start_z; + + switch (map_direction){ + case MAP_ELEMENT_DIRECTION_WEST: + cur_x += trackBlock[i].x; + cur_y += trackBlock[i].y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + cur_x += trackBlock[i].y; + cur_y -= trackBlock[i].x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + cur_x -= trackBlock[i].x; + cur_y -= trackBlock[i].y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + cur_x -= trackBlock[i].y; + cur_y += trackBlock[i].x; + break; + } + + cur_z += trackBlock[i].z; + + map_invalidate_tile_full(cur_x, cur_y); + + map_element = map_get_first_element_at(cur_x / 32, cur_y / 32); + success_map = NULL; + + do{ + if (map_element->base_height != cur_z / 8) + continue; + + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + continue; + + if ((map_element->properties.track.sequence & 0xF) != trackBlock[i].var_00) + continue; + + if (type == map_element->properties.track.type) + { + success_map = map_element; + break; + } + } while (!map_element_is_last_for_tile(map_element++)); + + if (success_map == NULL){ + return 1; + } + + if (i == 0 && output_element != NULL) + *output_element = map_element; + + if (flags & (1 << 0)){ + // Quadrant related ?? + map_element->type &= ~(1 << 6); + } + + if (flags & (1 << 1)){ + // Quadrant related ?? + map_element->type |= (1 << 6); + } + + if (flags & (1 << 2)){ + map_element->properties.track.colour &= 0xFC; + map_element->properties.track.colour |= extra_params & 0xFF; + } + + if (flags & (1 << 5)){ + map_element->properties.track.colour &= 0x0F; + map_element->properties.track.colour |= (extra_params & 0xFF) << 4; + } + + if (flags & (1 << 3)){ + map_element->properties.track.colour |= (1 << 3); + } + + if (flags & (1 << 4)){ + map_element->properties.track.colour &= 0xF7; + } + } + + return 0; } void sub_6C96C0() @@ -712,20 +950,23 @@ void sub_6C96C0() RCT2_CALLPROC_X(0x006C96C0, 0, 0, 0, 0, 0, 0, 0); } -static void sub_6C9627() +void sub_6C9627() { switch (RCT2_GLOBAL(0x00F440A6, uint8)) { case 3: + { + int x = RCT2_GLOBAL(0x00F440A8, uint16), y = RCT2_GLOBAL(0x00F440AA, uint16), z = RCT2_GLOBAL(0x00F440AC, uint16); sub_6C683D( - RCT2_GLOBAL(0x00F440A8, uint16), - RCT2_GLOBAL(0x00F440AA, uint16), - RCT2_GLOBAL(0x00F440AC, uint16), - RCT2_GLOBAL(0x00F440AE, uint8) & 3, + &x, + &y, + &z, + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) & 3, RCT2_GLOBAL(0x00F440AF, uint8), 0, 0, 1 - ); + ); + } break; case 6: case 7: @@ -847,13 +1088,15 @@ int ride_modify_maze(rct_map_element *mapElement, int x, int y) * * rct2: 0x006CC056 */ -int ride_modify(rct_map_element *mapElement, int x, int y) +int ride_modify(rct_xy_element *input) { - int rideIndex, z, direction, type; + int rideIndex, x, y, z, direction, type; + rct_xy_element mapElement, endOfTrackElement; rct_ride *ride; rct_window *constructionWindow; - rideIndex = mapElement->properties.track.ride_index; + mapElement = *input; + rideIndex = mapElement.element->properties.track.ride_index; ride = GET_RIDE(rideIndex); if (!ride_check_if_construction_allowed(ride)) @@ -866,7 +1109,7 @@ int ride_modify(rct_map_element *mapElement, int x, int y) return 0; } - if (ride->lifecycle_flags & RIDE_LIFECYCLE_19) { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) { RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 8, uint32) = ride->name_arguments; window_error_open(STR_CANT_START_CONSTRUCTION_ON, STR_THIS_RIDE_CANNOT_BE_MODIFIED); @@ -877,35 +1120,39 @@ int ride_modify(rct_map_element *mapElement, int x, int y) ride_remove_peeps(rideIndex); // Check if element is a station entrance or exit - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_ENTRANCE) - return ride_modify_entrance_or_exit(mapElement, x, y); + if (map_element_get_type(mapElement.element) == MAP_ELEMENT_TYPE_ENTRANCE) + return ride_modify_entrance_or_exit(mapElement.element, mapElement.x, mapElement.y); constructionWindow = ride_create_or_find_construction_window(rideIndex); if (ride->type == RIDE_TYPE_MAZE) - return ride_modify_maze(mapElement, x, y); + return ride_modify_maze(mapElement.element, mapElement.x, mapElement.y); - if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS,uint64)[ride->type] & 0x100) { - int outX = x, outY = y; - mapElement = ride_find_track_gap(mapElement, &outX, &outY); + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_8)) { + if (ride_find_track_gap(&mapElement, &endOfTrackElement)) + mapElement = endOfTrackElement; } - z = mapElement->base_height * 8; - direction = mapElement->type & 3; - type = mapElement->properties.track.type; - sub_6C683D(x, y, z, direction, type, 0, 0, 0); + x = mapElement.x; + y = mapElement.y; + z = mapElement.element->base_height * 8; + direction = mapElement.element->type & 3; + type = mapElement.element->properties.track.type; + + if (sub_6C683D(&x, &y, &z, direction, type, 0, 0, 0)) + return 0; RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; RCT2_GLOBAL(0x00F440A6, uint8) = 3; RCT2_GLOBAL(0x00F440A8, uint16) = x; RCT2_GLOBAL(0x00F440AA, uint16) = y; RCT2_GLOBAL(0x00F440AC, uint16) = z; - RCT2_GLOBAL(0x00F440AE, uint8) = direction; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = direction; RCT2_GLOBAL(0x00F440AF, uint8) = type; RCT2_GLOBAL(0x00F440B0, uint8) = 0; RCT2_GLOBAL(0x00F440B1, uint8) = 0; - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x8000) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15)) { sub_6C84CE(); return 1; } @@ -920,7 +1167,7 @@ int ride_modify(rct_map_element *mapElement, int x, int y) RCT2_GLOBAL(0x00F440A8, uint16) = x; RCT2_GLOBAL(0x00F440AA, uint16) = y; RCT2_GLOBAL(0x00F440AC, uint16) = z; - RCT2_GLOBAL(0x00F440AE, uint8) = direction; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = direction; RCT2_GLOBAL(0x00F440AF, uint8) = type; RCT2_GLOBAL(0x00F440B0, uint8) = 0; RCT2_GLOBAL(0x00F440B1, uint8) = 0; @@ -932,7 +1179,7 @@ int ride_modify(rct_map_element *mapElement, int x, int y) RCT2_GLOBAL(0x00F440A8, uint16) = x; RCT2_GLOBAL(0x00F440AA, uint16) = y; RCT2_GLOBAL(0x00F440AC, uint16) = z; - RCT2_GLOBAL(0x00F440AE, uint8) = direction; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = direction; RCT2_GLOBAL(0x00F440AF, uint8) = type; RCT2_GLOBAL(0x00F440B0, uint8) = 0; RCT2_GLOBAL(0x00F440B1, uint8) = 0; @@ -940,10 +1187,6 @@ int ride_modify(rct_map_element *mapElement, int x, int y) sub_6C84CE(); return 1; - - // Success stored in carry flag which can't be accessed after call using is macro - // RCT2_CALLPROC_X(0x006CC056, 0, 0, 0, (int)trackMapElement, 0, 0, 0); - // return 1; } /** @@ -983,7 +1226,7 @@ int sub_6CC3FB(int rideIndex) RCT2_GLOBAL(0x00F440B6, uint8) = 0; RCT2_GLOBAL(0x00F440B7, uint8) = 0; - RCT2_GLOBAL(0x00F440AE, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = 0; RCT2_GLOBAL(0x00F440A6, uint8) = 4; RCT2_GLOBAL(0x00F440B0, uint8) = 0; RCT2_GLOBAL(0x00F440B1, uint8) = 0; @@ -1008,9 +1251,8 @@ void ride_update_all() rct_ride *ride; int i; - // Remove all rides if certain flags are set (possible scenario editor?) - int *esi = (int*)0x9DCE9E; - if (esi[0x1BCA] & 2) { + // Remove all rides if scenario editor + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) { if (s6Info->var_000 <= 2) FOR_ALL_RIDES(i, ride) ride->type = RIDE_TYPE_NULL; @@ -1061,13 +1303,13 @@ static void ride_update(int rideIndex) ride->var_126 = ride->var_124; ride->var_124 = ride->var_120; ride->var_120 = 0; - ride->var_14D |= 1; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; ride->income_per_hour = ride_calculate_income_per_hour(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; if (ride->upkeep_cost != (money16)0xFFFF) - ride->profit = (money16)(ride->income_per_hour - ((money32)ride->upkeep_cost * 16)); + ride->profit = (ride->income_per_hour - ((money32)ride->upkeep_cost * 16)); } // Ride specific updates @@ -1084,6 +1326,30 @@ static void ride_update(int rideIndex) ride_breakdown_status_update(rideIndex); ride_inspection_update(ride); + + // Used to bring up the "real" ride window after a crash. Can be removed once vehicle_update is decompiled + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) { + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED_WINDOW_OPENED) == 0) { + ride->lifecycle_flags |= RIDE_LIFECYCLE_CRASHED_WINDOW_OPENED; + window_ride_main_open(rideIndex); + } + } + else if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED_WINDOW_OPENED) { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED_WINDOW_OPENED; + } + + if (ride->status == RIDE_STATUS_TESTING && gConfigGeneral.no_test_crashes) { + for (int i = 0; i < ride->num_vehicles; i++) { + rct_vehicle *vehicle = &(g_sprite_list[ride->vehicles[i]].vehicle); + + if (vehicle->status == VEHICLE_STATUS_CRASHED || vehicle->status == VEHICLE_STATUS_CRASHING) { + ride_set_status(rideIndex, RIDE_STATUS_CLOSED); + ride_set_status(rideIndex, RIDE_STATUS_CLOSED); + ride_set_status(rideIndex, RIDE_STATUS_TESTING); + break; + } + } + } } /** @@ -1101,7 +1367,7 @@ static void ride_chairlift_update(rct_ride *ride) if (ride->breakdown_reason_pending == 0) return; - ax = ride->var_0D0 * 2048; + ax = ride->operation_option * 2048; bx = ride->var_148; cx = bx + ax; ride->var_148 = cx; @@ -1119,6 +1385,40 @@ static void ride_chairlift_update(rct_ride *ride) map_invalidate_tile(x, y, z, z + (4 * 8)); } +/** + * rct2: 0x0069A3A2 + * edi: ride (in code as bytes offset from start of rides list) + * bl: happiness + */ +void ride_update_satisfaction(rct_ride* ride, uint8 happiness) { + ride->satisfaction_next += happiness; + ride->satisfaction_time_out++; + if (ride->satisfaction_time_out >= 20) { + ride->satisfaction = ride->satisfaction_next >> 2; + ride->satisfaction_next = 0; + ride->satisfaction_time_out = 0; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; + + } +} + +/* rct2: 0x0069A3D7 + * Updates the ride popularity + * edi : ride + * bl : pop_amount + * pop_amount can be zero if peep visited but did not purchase. + */ +void ride_update_popularity(rct_ride* ride, uint8 pop_amount){ + ride->popularity_next += pop_amount; + ride->popularity_time_out++; + if (ride->popularity_time_out < 25)return; + + ride->popularity = ride->popularity_next; + ride->popularity_next = 0; + ride->popularity_time_out = 0; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; +} + /** * * rct2: 0x006AC545 @@ -1153,10 +1453,12 @@ static void ride_spiral_slide_update(rct_ride *ride) mapElement = ride_get_station_start_track_element(ride, i); int rotation = ((mapElement->type & 3) << 2) | RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); - x += RCT2_GLOBAL(0x0098DDB8 + (rotation * 4), uint16); - y += RCT2_GLOBAL(0x0098DDBA + (rotation * 4), uint16); + x *= 32; + y *= 32; + x += RCT2_GLOBAL(0x0098DDB8 + (rotation * 4), sint16); + y += RCT2_GLOBAL(0x0098DDBA + (rotation * 4), sint16); - map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + gfx_invalidate_tile_if_zoomed(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); } } @@ -1217,13 +1519,35 @@ static void ride_inspection_update(rct_ride *ride) } } +static int get_age_penalty(rct_ride *ride) { + int years; + years = date_get_year(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) - ride->build_date); + switch (years) { + case 0: + return 0; + case 1: + return ride->unreliability_factor / 8; + case 2: + return ride->unreliability_factor / 4; + case 3: + case 4: + return ride->unreliability_factor / 2; + case 5: + case 6: + case 7: + return ride->unreliability_factor; + default: + return ride->unreliability_factor * 2; + } +} + /** * * rct2: 0x006AC622 */ static void ride_breakdown_update(int rideIndex) { - int agePenalty, years, ax, breakdownReason; + int breakdownReason, unreliabilityAccumulator; rct_ride *ride = GET_RIDE(rideIndex); if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 255) @@ -1239,10 +1563,11 @@ static void ride_breakdown_update(int rideIndex) ride->var_19C + ride->var_19D + ride->var_19E + + ride->var_19F + ride->var_1A0 + ride->var_1A2 + ride->var_1A3; - ride->var_199 = min(ax / 2, 100); + ride->downtime = min(ax / 2, 100); ride->var_1A3 = ride->var_1A2; ride->var_1A2 = ride->var_1A1; @@ -1252,7 +1577,7 @@ static void ride_breakdown_update(int rideIndex) ride->var_19E = ride->var_19D; ride->var_19D = ride->var_19C; ride->var_19C = 0; - ride->var_14D |= 32; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE; } if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) @@ -1261,37 +1586,17 @@ static void ride_breakdown_update(int rideIndex) return; // Calculate breakdown probability? - ax = ride->var_198; - agePenalty; - years = date_get_year(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) - ride->build_date); - switch (years) { - case 0: - agePenalty = 0; - break; - case 1: - agePenalty = ax >> 3; - break; - case 2: - agePenalty = ax >> 2; - break; - case 3: - agePenalty = ax >> 1; - break; - case 4: - case 5: - case 6: - agePenalty = ax >> 0; - break; - default: - agePenalty = ax << 1; - break; - } - ax += agePenalty; - ride->var_196 = max(0, ride->var_196 - ax); - ride->var_14D |= 32; + unreliabilityAccumulator = ride->unreliability_factor + get_age_penalty(ride); + ride->reliability = max(0, ride->reliability - unreliabilityAccumulator); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE; - // Random probability of a breakdown - if (ride->var_196 == 0 || (int)(scenario_rand() & 0x2FFFFF) <= 25856 - ride->var_196) { + // Random probability of a breakdown. Roughly this is 1 in + // + // (25000 - reliability) / 3 000 000 + // + // a 0.8% chance, less the breakdown factor which accumulates as the game + // continues. + if ((ride->reliability == 0 || (int)(scenario_rand() & 0x2FFFFF) <= 1 + RIDE_INITIAL_RELIABILITY - ride->reliability) && !gConfigCheat.disable_all_breakdowns) { breakdownReason = ride_get_new_breakdown_problem(ride); if (breakdownReason != -1) ride_prepare_breakdown(rideIndex, breakdownReason); @@ -1312,7 +1617,7 @@ static int ride_get_new_breakdown_problem(rct_ride *ride) RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8) == 0 ? 3 : 20; entry = ride_get_entry(ride); - if (entry->var_008 & 0x4000) + if (entry->flags & RIDE_ENTRY_FLAG_14) return -1; availableBreakdownProblems = RideAvailableBreakdowns[ride->type]; @@ -1342,16 +1647,19 @@ static int ride_get_new_breakdown_problem(rct_ride *ride) if (breakdownProblem != BREAKDOWN_BRAKES_FAILURE) return breakdownProblem; - // Breaks failure can not happen if block breaks are used (so long as there is more than one vehicle) - // However if this is the case, break failure should be taken out the equation, otherwise block brake + // Brakes failure can not happen if block brakes are used (so long as there is more than one vehicle) + // However if this is the case, brake failure should be taken out the equation, otherwise block brake // rides have a lower probability to break down due to a random implementation reason. if (ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED) if (ride->num_vehicles != 1) return -1; - // Again the probability is lower, this time if young or two other unknown reasons... + // If brakes failure is disabled, also take it out of the equation (see above comment why) + if (gConfigCheat.disable_brakes_failure) + return -1; + monthsOld = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint8) - ride->build_date; - if (monthsOld < 16 || ride->var_196 > 12800 || ride->lifecycle_flags & RIDE_LIFECYCLE_19) + if (monthsOld < 16 || ride->reliability > (50 << 8) || ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) return -1; return BREAKDOWN_BRAKES_FAILURE; @@ -1361,7 +1669,7 @@ static int ride_get_new_breakdown_problem(rct_ride *ride) * * rct2: 0x006B7348 */ -static void ride_prepare_breakdown(int rideIndex, int breakdownReason) +void ride_prepare_breakdown(int rideIndex, int breakdownReason) { int i; rct_ride *ride; @@ -1400,9 +1708,17 @@ static void ride_prepare_breakdown(int rideIndex, int breakdownReason) // Set flag on broken car vehicle = &(g_sprite_list[ride->vehicles[ride->broken_vehicle]].vehicle); - for (i = ride->broken_car; i > 0; i--) - vehicle = &(g_sprite_list[vehicle->next_vehicle_on_train].vehicle); - vehicle->var_48 |= 0x100; + for (i = ride->broken_car; i > 0; i--) { + if (vehicle->next_vehicle_on_train == (uint16)0xFFFFFFFF) { + vehicle = NULL; + break; + } + else { + vehicle = &(g_sprite_list[vehicle->next_vehicle_on_train].vehicle); + } + } + if (vehicle != NULL) + vehicle->var_48 |= 0x100; break; case BREAKDOWN_VEHICLE_MALFUNCTION: // Choose a random train @@ -1486,7 +1802,7 @@ static void ride_mechanic_status_update(int rideIndex, int mechanicStatus) breakdownReason == BREAKDOWN_CONTROL_FAILURE ) { ride->lifecycle_flags |= RIDE_LIFECYCLE_BROKEN_DOWN; - ride->var_14D |= 0x2C; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE | RIDE_INVALIDATE_RIDE_LIST | RIDE_INVALIDATE_RIDE_MAIN; ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING; ride->breakdown_reason = breakdownReason; ride_breakdown_add_news_item(rideIndex); @@ -1508,7 +1824,7 @@ static void ride_mechanic_status_update(int rideIndex, int mechanicStatus) mechanic->current_ride != rideIndex ) { ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING; - ride->var_14D |= 0x20; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE; ride_mechanic_status_update(rideIndex, RIDE_MECHANIC_STATUS_CALLING); } break; @@ -1524,7 +1840,7 @@ static void ride_mechanic_status_update(int rideIndex, int mechanicStatus) ) ) { ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING; - ride->var_14D |= 0x20; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE; ride_mechanic_status_update(rideIndex, RIDE_MECHANIC_STATUS_CALLING); } break; @@ -1543,9 +1859,9 @@ static void ride_call_mechanic(int rideIndex, rct_peep *mechanic, int forInspect peep_decrement_num_riders(mechanic); mechanic->state = forInspection ? PEEP_STATE_HEADING_TO_INSPECTION : PEEP_STATE_ANSWERING; peep_window_state_update(mechanic); - mechanic->var_2C = 0; + mechanic->sub_state = 0; ride->mechanic_status = RIDE_MECHANIC_STATUS_HEADING; - ride->var_14D |= 0x20; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE; ride->mechanic = mechanic->sprite_index; mechanic->current_ride = rideIndex; mechanic->current_ride_station = ride->inspection_station; @@ -1619,14 +1935,18 @@ rct_peep *find_closest_mechanic(int x, int y, int forInspection) if (peep->staff_type != STAFF_TYPE_MECHANIC) continue; - if (forInspection) { - if ((peep->state != PEEP_STATE_HEADING_TO_INSPECTION || peep->var_2C >= 4) && peep->state != PEEP_STATE_PATROLLING) + if (!forInspection) { + if (peep->state == PEEP_STATE_HEADING_TO_INSPECTION){ + if (peep->sub_state >= 4) + continue; + } + else if (peep->state != PEEP_STATE_PATROLLING) continue; - if (!(peep->staff_orders & 2)) + if (!(peep->staff_orders & STAFF_ORDERS_FIX_RIDES)) continue; } else { - if (peep->state != PEEP_STATE_PATROLLING && !(peep->staff_orders & 1)) + if (peep->state != PEEP_STATE_PATROLLING || !(peep->staff_orders & STAFF_ORDERS_INSPECT_RIDES)) continue; } @@ -1671,6 +1991,45 @@ rct_peep *ride_get_assigned_mechanic(rct_ride *ride) #pragma region Music functions +#define MAKE_TUNEID_LIST(...) (uint8[]){(countof(((uint8[]){__VA_ARGS__}))), __VA_ARGS__} + +//0x009AEF28 +uint8 *ride_music_style_tuneids[] = { + MAKE_TUNEID_LIST(13), // MUSIC_STYLE_DODGEMS_BEAT + MAKE_TUNEID_LIST(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), // MUSIC_STYLE_FAIRGROUND_ORGAN + MAKE_TUNEID_LIST(15), // MUSIC_STYLE_ROMAN_FANFARE + MAKE_TUNEID_LIST(16), // MUSIC_STYLE_ORIENTAL + MAKE_TUNEID_LIST(17), // MUSIC_STYLE_MARTIAN + MAKE_TUNEID_LIST(18), // MUSIC_STYLE_JUNGLE_DRUMS + MAKE_TUNEID_LIST(19), // MUSIC_STYLE_EGYPTIAN + MAKE_TUNEID_LIST(20), // MUSIC_STYLE_TOYLAND + MAKE_TUNEID_LIST(21), // MUSIC_STYLE_8 + MAKE_TUNEID_LIST(22), // MUSIC_STYLE_SPACE + MAKE_TUNEID_LIST(23), // MUSIC_STYLE_HORROR + MAKE_TUNEID_LIST(24), // MUSIC_STYLE_TECHNO + MAKE_TUNEID_LIST(25), // MUSIC_STYLE_GENTLE + MAKE_TUNEID_LIST(26), // MUSIC_STYLE_SUMMER + MAKE_TUNEID_LIST(27), // MUSIC_STYLE_WATER + MAKE_TUNEID_LIST(28), // MUSIC_STYLE_WILD_WEST + MAKE_TUNEID_LIST(29), // MUSIC_STYLE_JURASSIC + MAKE_TUNEID_LIST(30), // MUSIC_STYLE_ROCK + MAKE_TUNEID_LIST(31), // MUSIC_STYLE_RAGTIME + MAKE_TUNEID_LIST(32), // MUSIC_STYLE_FANTASY + MAKE_TUNEID_LIST(33), // MUSIC_STYLE_ROCK_STYLE_2 + MAKE_TUNEID_LIST(34), // MUSIC_STYLE_ICE + MAKE_TUNEID_LIST(35), // MUSIC_STYLE_SNOW + MAKE_TUNEID_LIST(36), // MUSIC_STYLE_CUSTOM_MUSIC_1 + MAKE_TUNEID_LIST(37), // MUSIC_STYLE_CUSTOM_MUSIC_2 + MAKE_TUNEID_LIST(38), // MUSIC_STYLE_MEDIEVAL + MAKE_TUNEID_LIST(39), // MUSIC_STYLE_URBAN + MAKE_TUNEID_LIST(40), // MUSIC_STYLE_ORGAN + MAKE_TUNEID_LIST(41), // MUSIC_STYLE_MECHANICAL + MAKE_TUNEID_LIST(42), // MUSIC_STYLE_MODERN + MAKE_TUNEID_LIST(43), // MUSIC_STYLE_PIRATES + MAKE_TUNEID_LIST(44), // MUSIC_STYLE_ROCK_STYLE_3 + MAKE_TUNEID_LIST(45), // MUSIC_STYLE_CANDY_STYLE +}; + /** * * rct2: 0x006ABE85 @@ -1722,7 +2081,7 @@ static void ride_music_update(int rideIndex) // Select random tune from available tunes for a music style (of course only merry-go-rounds have more than one tune) if (ride->music_tune_id == 255) { - uint8 *musicStyleTunes = RCT2_ADDRESS(0x009AEF28, uint8*)[ride->music]; + uint8 *musicStyleTunes = ride_music_style_tuneids[ride->music]; uint8 numTunes = *musicStyleTunes++; ride->music_tune_id = musicStyleTunes[scenario_rand() % numTunes]; ride->music_position = 0; @@ -1788,7 +2147,7 @@ void ride_measurement_update(rct_ride_measurement *measurement) return; measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING; - if (measurement->var_0B == vehicle->var_4B) + if (measurement->current_station == vehicle->current_station) measurement->current_item = 0; } @@ -1872,7 +2231,7 @@ void ride_measurements_update() vehicle = &(g_sprite_list[spriteIndex].vehicle); if (vehicle->status == VEHICLE_STATUS_DEPARTING || vehicle->status == VEHICLE_STATUS_STOPPING) { measurement->vehicle_index = j; - measurement->var_0B = vehicle->var_4B; + measurement->current_station = vehicle->current_station; measurement->flags |= RIDE_MEASUREMENT_FLAG_RUNNING; measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING; ride_measurement_update(measurement); @@ -1898,7 +2257,7 @@ rct_ride_measurement *ride_get_existing_measurement(int rideIndex) return NULL; } -rct_ride_measurement *ride_get_free_measurement() +int ride_get_free_measurement() { int i; rct_ride_measurement *measurement; @@ -1906,10 +2265,10 @@ rct_ride_measurement *ride_get_free_measurement() for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { measurement = GET_RIDE_MEASUREMENT(i); if (measurement->ride_index == 255) - return measurement; + return i; } - return NULL; + return -1; } /** @@ -1926,7 +2285,7 @@ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message ride = GET_RIDE(rideIndex); // Check if ride type supports data logging - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x200)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING)) { if (message != NULL) *message = STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE; return NULL; } @@ -1935,8 +2294,8 @@ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message measurement = ride_get_existing_measurement(rideIndex); if (measurement == NULL) { // Find a free measurement - measurement = ride_get_free_measurement(); - if (measurement == NULL) { + i = ride_get_free_measurement(); + if (i == -1) { // Use last recently used measurement for some other ride lruIndex = 0; lruTicks = 0xFFFFFFFF; @@ -1951,13 +2310,15 @@ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message i = lruIndex; measurement = GET_RIDE_MEASUREMENT(i); - ride->measurement_index = 255; + GET_RIDE(measurement->ride_index)->measurement_index = 255; + } else { + measurement = GET_RIDE_MEASUREMENT(i); } - + measurement->ride_index = rideIndex; ride->measurement_index = i; measurement->flags = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x80) + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) measurement->flags |= RIDE_MEASUREMENT_FLAG_G_FORCES; measurement->num_items = 0; measurement->current_item = 0; @@ -1991,8 +2352,8 @@ track_colour ride_get_track_colour(rct_ride *ride, int colourScheme) vehicle_colour ride_get_vehicle_colour(rct_ride *ride, int vehicleIndex) { vehicle_colour result; - result.main = ride->vehicle_colours[vehicleIndex] & 0xFF; - result.additional_1 = ride->vehicle_colours[vehicleIndex] >> 8; + result.main = ride->vehicle_colours[vehicleIndex].body_colour; + result.additional_1 = ride->vehicle_colours[vehicleIndex].trim_colour; result.additional_2 = ride->vehicle_colours_extended[vehicleIndex]; return result; } @@ -2015,8 +2376,8 @@ void ride_check_all_reachable() if (ride->status != RIDE_STATUS_OPEN || ride->connected_message_throttle != 0) continue; - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x20000) - ride_shop_connected(ride, i); + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) + ride_shop_connected(ride, i); else ride_entrance_exit_connected(ride, i); } @@ -2026,29 +2387,35 @@ void ride_check_all_reachable() * rct2: 0x006B7C59 * @return 1 if the coordinate is reachable or has no entrance, 0 otherwise */ -static int ride_entrance_exit_is_reachable(uint16 coordinate, rct_ride* ride, int index) { - int x = ((coordinate >> 8) & 0xFF) << 5, // cx - y = (coordinate & 0xFF) << 5; // ax - uint8 station_height = ride->station_heights[index]; - int tile_idx = ((x << 8) | y) >> 5; - rct_map_element* tile = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[tile_idx]; +static int ride_entrance_exit_is_reachable(uint16 coordinate, rct_ride* ride, int index) +{ + int x, y, z; + rct_map_element *mapElement; - while(1) { - uint8 element_type = tile->type & MAP_ELEMENT_TYPE_MASK; - if (element_type == MAP_ELEMENT_TYPE_ENTRANCE && station_height == tile->base_height) { - break; - } else if (tile->flags & MAP_ELEMENT_FLAG_LAST_TILE) { - return 1; - } - tile++; + x = coordinate & 0xFF; + y = (coordinate >> 8) & 0xFF; + z = ride->station_heights[index]; + mapElement = map_get_first_element_at(x, y); + + for (;;) { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE && z == mapElement->base_height) { + break; + } else if (map_element_is_last_for_tile(mapElement)) { + return 1; + } + mapElement++; } - uint8 face_direction = tile->type & 3; - y -= RCT2_ADDRESS(0x00993CCC, sint16)[face_direction * 2]; - x -= RCT2_ADDRESS(0x00993CCE, sint16)[face_direction * 2]; - tile_idx = ((x << 8) | y) >> 5; + uint8 face_direction = mapElement->type & 3; - return map_coord_is_connected(tile_idx, station_height, face_direction); + x *= 32; + y *= 32; + x -= RCT2_ADDRESS(0x00993CCC, sint16)[face_direction * 2]; + y -= RCT2_ADDRESS(0x00993CCE, sint16)[face_direction * 2]; + x /= 32; + y /= 32; + + return map_coord_is_connected(x, y, z, face_direction); } static void ride_entrance_exit_connected(rct_ride* ride, int ride_idx) @@ -2081,64 +2448,66 @@ static void ride_entrance_exit_connected(rct_ride* ride, int ride_idx) static void ride_shop_connected(rct_ride* ride, int ride_idx) { - rct_ride* ride_back = ride; + int x, y, count; + rct_map_element *mapElement; + uint16 coordinate = ride->station_starts[0]; if (coordinate == 0xFFFF) return; - int x = ((coordinate >> 8) & 0xFF) << 5, // cx - y = (coordinate & 0xFF) << 5; // ax + x = (coordinate & 0xFF); + y = (coordinate >> 8) & 0xFF; - rct_map_element* tile = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[coordinate]; - - for (; ; tile++){ - uint8 element_type = tile->type & MAP_ELEMENT_TYPE_MASK; - if(element_type == MAP_ELEMENT_TYPE_TRACK && tile->properties.track.ride_index == ride_idx) - break; - if(tile->flags & MAP_ELEMENT_FLAG_LAST_TILE) - return; - } + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK && mapElement->properties.track.ride_index == ride_idx) + break; + } while (!map_element_is_last_for_tile(mapElement++)); uint16 entrance_directions = 0; - uint8 track_type = tile->properties.track.type; - ride = &g_ride_list[tile->properties.track.ride_index]; - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x80000) { + uint8 track_type = mapElement->properties.track.type; + ride = &g_ride_list[mapElement->properties.track.ride_index]; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_FOOD)) { entrance_directions = RCT2_ADDRESS(0x0099CA64, uint8)[track_type * 16]; - } else { + } else { entrance_directions = RCT2_ADDRESS(0x0099BA64, uint8)[track_type * 16]; - } + } - - uint8 tile_direction = tile->type & MAP_ELEMENT_DIRECTION_MASK; + uint8 tile_direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; entrance_directions <<= tile_direction; entrance_directions = ((entrance_directions >> 12) | entrance_directions) & 0xF; - // now each bit in entrance_directions stands for an entrance direction to check + // Now each bit in entrance_directions stands for an entrance direction to check if (entrance_directions == 0) return; - for (int count = 0; entrance_directions != 0; ++count) { + // Turn x, y from tiles into units + x *= 32; + y *= 32; + + for (count = 0; entrance_directions != 0; count++) { if (!(entrance_directions & 1)) { entrance_directions >>= 1; - continue; - } + continue; + } entrance_directions >>= 1; - uint8 face_direction = count ^ 2; // flip direction north<->south, east<->west - int y2 = y - RCT2_ADDRESS(0x00993CCC, sint16)[face_direction * 2]; - int x2 = x - RCT2_ADDRESS(0x00993CCE, sint16)[face_direction * 2]; - int tile_idx = ((x2 << 8) | y2) >> 5; + // Flip direction north<->south, east<->west + uint8 face_direction = count ^ 2; - if (map_coord_is_connected(tile_idx, tile->base_height, face_direction)) - return; - } - - // name of ride is parameter of the format string - RCT2_GLOBAL(0x013CE952, uint16) = ride->name; + int y2 = y - RCT2_ADDRESS(0x00993CCE, sint16)[face_direction * 2]; + int x2 = x - RCT2_ADDRESS(0x00993CCC, sint16)[face_direction * 2]; + + if (map_coord_is_connected(x2 / 32, y2 / 32, mapElement->base_height, face_direction)) + return; + } + + // Name of ride is parameter of the format string + RCT2_GLOBAL(0x013CE952, uint16) = ride->name; RCT2_GLOBAL(0x013CE954, uint32) = ride->name_arguments; news_item_add_to_queue(1, STR_ENTRANCE_NOT_CONNECTED, ride_idx); - ride->connected_message_throttle = 3; + ride->connected_message_throttle = 3; } #pragma endregion @@ -2237,7 +2606,7 @@ static void ride_entrance_set_map_tooltip(rct_map_element *mapElement) void ride_set_map_tooltip(rct_map_element *mapElement) { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_ENTRANCE) { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { ride_entrance_set_map_tooltip(mapElement); } else { if ( @@ -2336,32 +2705,34 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint uint8 vol1 = -1; uint8 vol2 = -1; - if (pany < 0) { - pany = -pany; + int panx2 = panx; + int pany2 = pany; + if (pany2 < 0) { + pany2 = -pany2; } - if (pany > 6143) { - pany = 6143; + if (pany2 > 6143) { + pany2 = 6143; } - pany -= 2048; - if (pany > 0) { - pany = -((pany / 4) - 1024) / 4; - vol1 = (uint8)pany; - if (pany >= 256) { + pany2 -= 2048; + if (pany2 > 0) { + pany2 = -((pany2 / 4) - 1024) / 4; + vol1 = (uint8)pany2; + if (pany2 >= 256) { vol1 = -1; } } - if (panx < 0) { - panx = -panx; + if (panx2 < 0) { + panx2 = -panx2; } - if (panx > 6143) { - panx = 6143; + if (panx2 > 6143) { + panx2 = 6143; } - panx -= 2048; - if (panx > 0) { - panx = -((panx / 4) - 1024) / 4; - vol2 = (uint8)panx; - if (panx >= 256) { + panx2 -= 2048; + if (panx2 > 0) { + panx2 = -((panx2 / 4) - 1024) / 4; + vol2 = (uint8)panx2; + if (panx2 >= 256) { vol2 = -1; } } @@ -2391,8 +2762,8 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint ride_music++; channel++; if (channel >= AUDIO_MAX_RIDE_MUSIC) { - rct_ride_music_info* ride_music_info = &RCT2_GLOBAL(0x009AF1C8, rct_ride_music_info*)[*tuneId]; - a1 = position + ride_music_info->var_4; + rct_ride_music_info* ride_music_info = ride_music_info_list[*tuneId]; + a1 = position + ride_music_info->offset; goto label51; } } @@ -2415,7 +2786,7 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint RCT2_GLOBAL(0x014241BC, uint32) = 0; #endif label51: - if (a1 < RCT2_GLOBAL(0x009AF1C8, rct_ride_music_info*)[*tuneId].var_0) { + if (a1 < ride_music_info_list[*tuneId]->length) { position = a1; rct_ride_music_params* ride_music_params = gRideMusicParamsListEnd;//RCT2_GLOBAL(0x009AF42C, rct_ride_music_params*); if (ride_music_params < &gRideMusicParamsList[AUDIO_MAX_RIDE_MUSIC]/*(rct_ride_music_params*)0x009AF46C*/) { @@ -2434,9 +2805,9 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint } else { label58: ; - rct_ride_music_info* ride_music_info = &RCT2_GLOBAL(0x009AF1C8, rct_ride_music_info*)[*tuneId]; - position += ride_music_info->var_4; - if (position < ride_music_info->var_0) { + rct_ride_music_info* ride_music_info = ride_music_info_list[*tuneId]; + position += ride_music_info->offset; + if (position < ride_music_info->length) { return position; } else { *tuneId = 0xFF; @@ -2447,6 +2818,58 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint return position; } +#define INIT_MUSIC_INFO(pathid, offset, length, unknown) (rct_ride_music_info[]){length, offset, pathid, unknown} + +//0x009AF1C8 +rct_ride_music_info* ride_music_info_list[] = { + INIT_MUSIC_INFO(PATH_ID_CSS4, 1378, 8139054, 0), + INIT_MUSIC_INFO(PATH_ID_CSS5, 1378, 7796656, 0), + INIT_MUSIC_INFO(PATH_ID_CSS6, 1378, 15787850, 0), + INIT_MUSIC_INFO(PATH_ID_CSS7, 1378, 15331658, 0), + INIT_MUSIC_INFO(PATH_ID_CSS8, 1378, 17503414, 0), + INIT_MUSIC_INFO(PATH_ID_CSS9, 1378, 7005802, 0), + INIT_MUSIC_INFO(PATH_ID_CSS10, 1378, 0, 0), + INIT_MUSIC_INFO(PATH_ID_CSS11, 1378, 7023288, 0), + INIT_MUSIC_INFO(PATH_ID_CSS12, 1378, 2767948, 0), + INIT_MUSIC_INFO(PATH_ID_CSS13, 1378, 3373390, 0), + INIT_MUSIC_INFO(PATH_ID_CSS14, 1378, 20783042, 0), + INIT_MUSIC_INFO(PATH_ID_CSS15, 1378, 10009312, 0), + INIT_MUSIC_INFO(PATH_ID_CSS16, 1378, 0, 0), + INIT_MUSIC_INFO(PATH_ID_CSS3, 689, 1244886, 1), + INIT_MUSIC_INFO(PATH_ID_CSS17, 2756, -1, 0), + INIT_MUSIC_INFO(PATH_ID_CSS18, 2756, 8429568, 1), + INIT_MUSIC_INFO(PATH_ID_CSS19, 2756, 10143784, 1), + INIT_MUSIC_INFO(PATH_ID_CSS20, 2756, 12271656, 1), + INIT_MUSIC_INFO(PATH_ID_CSS21, 2756, 9680968, 1), + INIT_MUSIC_INFO(PATH_ID_CSS22, 2756, 10062056, 1), + INIT_MUSIC_INFO(PATH_ID_CSS23, 2756, 11067432, 1), + INIT_MUSIC_INFO(PATH_ID_CSS24, 2756, 12427456, 0), + INIT_MUSIC_INFO(PATH_ID_CSS25, 2756, 15181512, 1), + INIT_MUSIC_INFO(PATH_ID_CSS26, 2756, 10694816, 1), + INIT_MUSIC_INFO(PATH_ID_CSS27, 2756, 10421232, 1), + INIT_MUSIC_INFO(PATH_ID_CSS28, 2756, 13118376, 1), + INIT_MUSIC_INFO(PATH_ID_CSS29, 2756, 15310892, 1), + INIT_MUSIC_INFO(PATH_ID_CSS30, 2756, 10215464, 1), + INIT_MUSIC_INFO(PATH_ID_CSS31, 2756, 11510316, 1), + INIT_MUSIC_INFO(PATH_ID_CSS32, 2756, 11771944, 1), + INIT_MUSIC_INFO(PATH_ID_CSS33, 2756, 10759724, 1), + INIT_MUSIC_INFO(PATH_ID_CSS34, 2756, 14030716, 1), + INIT_MUSIC_INFO(PATH_ID_CSS35, 2756, 11642576, 1), + INIT_MUSIC_INFO(PATH_ID_CSS36, 2756, 8953764, 1), + INIT_MUSIC_INFO(PATH_ID_CSS37, 2756, 13303852, 1), + INIT_MUSIC_INFO(PATH_ID_CSS38, 2756, 10093888, 1), + INIT_MUSIC_INFO(PATH_ID_CUSTOM1, 2756, 0, 1), + INIT_MUSIC_INFO(PATH_ID_CUSTOM2, 2756, 0, 1), + INIT_MUSIC_INFO(PATH_ID_CSS39, 2756, 7531564, 1), + INIT_MUSIC_INFO(PATH_ID_CSS40, 1378, 5291306, 1), + INIT_MUSIC_INFO(PATH_ID_CSS41, 2756, 27860700, 1), + INIT_MUSIC_INFO(PATH_ID_CSS42, 2756, 6774090, 1), + INIT_MUSIC_INFO(PATH_ID_CSS43, 2756, 15630412, 1), + INIT_MUSIC_INFO(PATH_ID_CSS44, 2756, 8209704, 1), + INIT_MUSIC_INFO(PATH_ID_CSS45, 2756, 10006740, 1), + INIT_MUSIC_INFO(PATH_ID_CSS46, 2756, 6772776, 1), +}; + /** * Play/update ride music based on structs updated in 0x006BC3AC * rct2: 0x006BC6D8 @@ -2465,7 +2888,7 @@ void ride_music_update_final() rct_ride_music_params* ride_music_params = &gRideMusicParamsList[0];//&RCT2_GLOBAL(0x009AF430, rct_ride_music_params); while (ride_music_params < gRideMusicParamsListEnd/*RCT2_GLOBAL(0x009AF42C, rct_ride_music_params*)*/) { if (ride_music_params->rideid != (uint8)-1) { - rct_ride_music_info* ride_music_info = &RCT2_GLOBAL(0x009AF1C8, rct_ride_music_info*)[ride_music_params->tuneid]; + rct_ride_music_info* ride_music_info = ride_music_info_list[ride_music_params->tuneid]; if (RCT2_ADDRESS(0x009AA0B1, uint8*)[ride_music_info->pathid]) { // file_on_cdrom[] v8++; if (v9 >= ride_music_params->volume) { @@ -2548,10 +2971,10 @@ void ride_music_update_final() ride_music++; channel++; if (channel >= AUDIO_MAX_RIDE_MUSIC) { - rct_ride_music_info* ride_music_info = &RCT2_GLOBAL(0x009AF1C8, rct_ride_music_info*)[ride_music_params->tuneid]; + rct_ride_music_info* ride_music_info = ride_music_info_list[ride_music_params->tuneid]; #ifdef USE_MIXER rct_ride_music* ride_music = &gRideMusicList[ebx]; - ride_music->sound_channel = Mixer_Play_Music(ride_music_info->pathid); + ride_music->sound_channel = Mixer_Play_Music(ride_music_info->pathid, MIXER_LOOP_NONE, true); if (ride_music->sound_channel) { ride_music->volume = ride_music_params->volume; ride_music->pan = ride_music_params->pan; @@ -2567,7 +2990,7 @@ void ride_music_update_final() } Mixer_Channel_SetOffset(ride_music->sound_channel, offset); } else { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) = 0; + //RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) = 0; } #else const char* filename = get_file_path(ride_music_info->pathid); @@ -2654,4 +3077,1434 @@ void ride_music_update_final() } } -#pragma endregion \ No newline at end of file +#pragma endregion + +/* rct2: 0x006B5559 */ +void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 4; + + uint8 ride_id = *edx & 0xFF; + rct_ride* ride = GET_RIDE(ride_id); + + uint8 flags = *ebx & 0xFF; + uint8 new_value = (*ebx >> 8) & 0xFF; + + uint8 setting = (*edx >> 8) & 0xFF; + + if (setting == 0){ + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN){ + RCT2_GLOBAL(0x141E9AC, uint16) = 1796; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (ride->status != RIDE_STATUS_CLOSED){ + RCT2_GLOBAL(0x141E9AC, uint16) = 1006; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS){ + if (setting == 0 || setting == 4 || setting == 8 || setting == 9) + { + RCT2_GLOBAL(0x141E9AC, uint16) = 1797; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if (setting == 9 && + ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT && + new_value > 1){ + RCT2_GLOBAL(0x141E9AC, uint16) = 3141; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (flags == 0){ + *ebx = 0; + return; + } + + switch (setting){ + case 0: + RCT2_CALLPROC_X(0x006B59C6, 0, 0, 0, ride_id, 0, 0, 0); + ride_clear_for_construction(ride_id); + ride_remove_peeps(ride_id); + + rct_ride_type* ride_entry = GET_RIDE_ENTRY(ride->subtype); + const uint8* available_modes = RideAvailableModes; + + for (int i = 0; i < ride->type; i++) { + while (*(available_modes++) != 255) {} + } + if (ride_entry->flags & RIDE_ENTRY_FLAG_17){ + available_modes += 2; + } + + uint8 default_mode = available_modes[0]; + for (; *available_modes != 0xFF; available_modes++){ + if (*available_modes == new_value) + break; + } + + if (*available_modes == 0xFF) new_value = default_mode; + + if (available_modes[1] == 0xFF){ + if (ride_entry->flags & RIDE_ENTRY_FLAG_15) + new_value = default_mode; + } + + ride->mode = new_value; + RCT2_CALLPROC_X(0x6DD57D, 0, 0, 0, ride_id, 0, 0, 0); + break; + case 1: + ride->depart_flags = new_value; + break; + case 2: + ride->min_waiting_time = new_value; + ride->max_waiting_time = max(new_value, ride->max_waiting_time); + break; + case 3: + ride->max_waiting_time = new_value; + ride->min_waiting_time = min(new_value, ride->min_waiting_time); + break; + case 4: + RCT2_CALLPROC_X(0x006B59C6, 0, 0, 0, ride_id, 0, 0, 0); + ride->time_limit = new_value; + break; + case 5: + ride->inspection_interval = new_value; + break; + case 6: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_MUSIC; + if (new_value){ + ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + } + break; + case 7: + if (new_value != ride->music){ + ride->music = new_value; + ride->music_tune_id = 0xFF; + } + break; + case 8: + if (new_value != ride->lift_hill_speed){ + ride->lift_hill_speed = new_value; + RCT2_CALLPROC_X(0x006B59C6, 0, 0, 0, ride_id, 0, 0, 0); + } + break; + case 9: + if (new_value != ride->num_circuits){ + ride->num_circuits = new_value; + RCT2_CALLPROC_X(0x006B59C6, 0, 0, 0, ride_id, 0, 0, 0); + } + break; + } + + window_invalidate_by_number(WC_RIDE, ride_id); + *ebx = 0; +} + +/** + * + * rct2: 0x006B4CC1 + */ +int ride_mode_check_valid_station_numbers(rct_ride *ride) +{ + uint8 no_stations = 0; + for (uint8 station_index = 0; station_index < 4; ++station_index){ + if (ride->station_starts[station_index] != 0xFFFF)no_stations++; + } + + switch (ride->mode){ + case RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE: + case RIDE_MODE_POWERED_LAUNCH_PASSTROUGH: + case RIDE_MODE_POWERED_LAUNCH: + case RIDE_MODE_LIM_POWERED_LAUNCH: + if (no_stations <= 1) return 1; + RCT2_GLOBAL(0x141E9AC, uint16) = 1015; + return 0; + case RIDE_MODE_SHUTTLE: + if (no_stations >= 2) return 1; + RCT2_GLOBAL(0x141E9AC, uint16) = 1016; + return 0; + } + + if (ride->type == RIDE_TYPE_GO_KARTS || ride->type == RIDE_TYPE_MINI_GOLF){ + if (no_stations <= 1) return 1; + RCT2_GLOBAL(0x141E9AC, uint16) = 1015; + return 0; + } + + return 1; +} + +/* returns stationIndex of first station on success + * -1 on failure. + */ +int ride_mode_check_station_present(rct_ride* ride){ + int stationIndex = -1; + for (int i = 0; i < 4; i++) { + if (ride->station_starts[i] != 0xFFFF) { + stationIndex = i; + break; + } + } + + if (stationIndex == -1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NOT_YET_CONSTRUCTED; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15)) + return -1; + + if (ride->type == RIDE_TYPE_MAZE) + return -1; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_REQUIRES_A_STATION_PLATFORM; + return -1; + } + + return stationIndex; +} + +/** + * + * rct2: 0x006B5872 + */ +int ride_check_for_entrance_exit(int rideIndex) +{ + rct_ride* ride = GET_RIDE(rideIndex); + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) + return 1; + + int i; + uint8 entrance = 0; + uint8 exit = 0; + for (i = 0; i < 4; i++) { + if (ride->station_starts[i] == 0xFFFF) + continue; + + if (ride->entrances[i] != 0xFFFF) { + entrance = 1; + } + + if (ride->exits[i] != 0xFFFF) { + exit = 1; + } + + // If station start and no entrance/exit + // Sets same error message as no entrance + if (ride->exits[i] == 0xFFFF && ride->entrances[i] == 0xFFFF){ + entrance = 0; + break; + } + } + + if (entrance == 0){ + RCT2_GLOBAL(0x141E9AC, uint16) = 1146; + return 0; + } + + if (exit == 0){ + RCT2_GLOBAL(0x141E9AC, uint16) = 1147; + return 0; + } + + return 1; +} + +/** + * + * rct2: 0x006B5952 + */ +void sub_6B5952(int rideIndex) +{ + RCT2_CALLPROC_X(0x006B5952, 0, 0, 0, rideIndex, 0, 0, 0); +} + +/** + * + * rct2: 0x006D3319 + */ +int ride_check_block_brakes(rct_xy_element *input, rct_xy_element *output) +{ + int rideIndex, type; + rct_xy_element trackElement, nextTrackElement; + rct_map_element *loopTrackElement; + rct_window *w; + + trackElement = *input; + rideIndex = trackElement.element->properties.track.ride_index; + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && RCT2_GLOBAL(0x00F440A6, uint8) != 0 && RCT2_GLOBAL(0x00F440A7, uint8) == rideIndex) + sub_6C9627(); + + loopTrackElement = NULL; + while (1) { + if (!track_get_next(&trackElement, &nextTrackElement)) { + // Not sure why this is the case... + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; + *output = trackElement; + return 0; + } + + if (nextTrackElement.element->properties.track.type == 216) { + type = trackElement.element->properties.track.type; + if (type == 1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; + *output = nextTrackElement; + return 0; + } + if (type == 216) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_EACH_OTHER; + *output = nextTrackElement; + return 0; + } + if ((trackElement.element->type & 0x80) && type != 209 && type != 210) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_THE_TOP_OF_THIS_LIFT_HILL; + *output = nextTrackElement; + return 0; + } + } + + trackElement = nextTrackElement; + if (loopTrackElement == NULL) + loopTrackElement = trackElement.element; + else if (loopTrackElement == trackElement.element) + break; + } + + return 1; +} + +/** + * + * rct2: 0x006CB149 + */ +int ride_check_track_suitability_a(rct_xy_element *input, rct_xy_element *output) +{ + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB149, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = (uint16)eax; + output->y = (uint16)ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; +} + +/** + * + * rct2: 0x006CB1D3 + */ +int ride_check_track_suitability_b(rct_xy_element *input, rct_xy_element *output) +{ + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB1D3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = (uint16)eax; + output->y = (uint16)ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; +} + +/** + * + * rct2: 0x006CB25D + */ +int ride_check_station_length(rct_xy_element *input, rct_xy_element *output) +{ + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + // This function has a bug. If the station length is too short and it is + // the last station of a ride it will return a pointer to the map_element + // where the station piece should go. Instead it should pass the map_element + // of the last good station piece. This can cause null pointer dereferences + // and cause the map to move to the top left hand corner. + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB25D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = (uint16)eax; + output->y = (uint16)ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; +} + +/** + * + * rct2: 0x006CB2DA + */ +int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *output) +{ + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB2DA, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = (uint16)eax; + output->y = (uint16)ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; +} + +/** + * + * rct2: 0x006B4D26 + */ +void sub_6B4D26(int rideIndex, rct_xy_element *startElement) +{ + RCT2_CALLPROC_X(0x006B4D26, startElement->x, 0, startElement->y, rideIndex, (int)startElement->element, 0, 0); return; + + rct_xy_element currentElement; + rct_ride *ride; + int trackType; + + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_BOAT_RIDE) { + + } else if (ride->type != RIDE_TYPE_MAZE) { + + } + + if ( + ( + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) && + !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) + ) { + // Set flag on track pieces where a train can start + currentElement = *startElement; + do { + trackType = currentElement.element->properties.track.type; + switch (trackType) { + case 1: // end of station + case 123: // cable lift hill + case 9: // 25deg up to flat + case 63: // 60deg up to flat + case 147: // diag 25deg up to flat + case 155: // diag 60deg up to flat + case 216: // block brakes + currentElement.element->flags &= ~(1 << 5); + break; + } + } while (track_get_next(¤tElement, ¤tElement) && currentElement.element != startElement->element); + } +} + +/** + * + * rct2: 0x006DD84C + */ +int sub_6DD84C(rct_ride *ride, int rideIndex, rct_xy_element *element, int isApplying) +{ + return RCT2_CALLPROC_X(0x006DD84C, element->x, isApplying, element->y, rideIndex, (int)ride, (int)element->element, 0) & 0x100; +} + +/** + * + * rct2: 0x006DF4D4 + */ +int sub_6DF4D4(rct_ride *ride, rct_xy_element *element, int isApplying) +{ + return RCT2_CALLPROC_X(0x006DF4D4, element->x, isApplying, element->y, 0, (int)ride, (int)element->element, 0) & 0x100; +} + +/** + * + * rct2: 0x006B51C0 + */ +void loc_6B51C0(int rideIndex) +{ + int i, x, y, z; + rct_ride *ride; + rct_xy_element trackElement; + rct_window *w; + + ride = GET_RIDE(rideIndex); + + if (RCT2_GLOBAL(0x0141F568, uint8) != RCT2_GLOBAL(0x013CA740, uint8)) + return; + + w = window_get_main(); + if (w == NULL) + return; + + sint8 entranceOrExit = -1; + for (i = 0; i < 4; i++) { + if (ride->station_starts[i] == 0xFFFF) + continue; + + if (ride->entrances[i] == 0xFFFF) { + entranceOrExit = 0; + break; + } + + if (ride->exits[i] == 0xFFFF) { + entranceOrExit = 1; + break; + } + } + + if (entranceOrExit == -1) + return; + + if (ride->type != RIDE_TYPE_MAZE) { + x = (ride->station_starts[i] & 0xFF) * 32; + y = (ride->station_starts[i] >> 8) * 32; + z = ride->station_heights[i] * 8; + window_scroll_to_location(w, x, y, z); + + sub_6CAF80(rideIndex, &trackElement); + ride_find_track_gap(&trackElement, &trackElement); + ride_modify(&trackElement); + + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL) + window_event_mouse_up_call(w, 29 + entranceOrExit); + } +} + +/** + * + * rct2: 0x006B528A + */ +void loc_6B528A(rct_xy_element *trackElement) +{ + rct_ride *ride; + rct_window *w; + + ride = GET_RIDE(trackElement->element->properties.track.ride_index); + + if (RCT2_GLOBAL(0x0141F568, uint8) != RCT2_GLOBAL(0x013CA740, uint8)) + return; + + w = window_get_main(); + if (w == NULL) + return; + + window_scroll_to_location(w, trackElement->x, trackElement->y, trackElement->element->base_height * 8); + ride_modify(trackElement); +} + +/** + * + * rct2: 0x006B4F6B + */ +rct_map_element *loc_6B4F6B(int rideIndex, int x, int y) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + uint32 unk = mapElement->properties.track.type << 4; + if (RCT2_GLOBAL(0x00F43484, uint32) & 0x80000) { + if (!(RCT2_ADDRESS(0x0099CA64, uint8)[unk] & 0x10)) + continue; + } else { + if (!(RCT2_ADDRESS(0x0099BA64, uint8)[unk] & 0x10)) + continue; + } + + if (mapElement->properties.track.ride_index == rideIndex) + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + +int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying) +{ + int stationIndex; + rct_ride *ride; + rct_xy_element trackElement, problematicTrackElement; + + ride = GET_RIDE(rideIndex); + + window_close_by_class(WC_RIDE_CONSTRUCTION); + + stationIndex = ride_mode_check_station_present(ride); + if (stationIndex == -1)return 0; + + if (!ride_mode_check_valid_station_numbers(ride)) + return 0; + + if (!ride_check_for_entrance_exit(rideIndex)) { + loc_6B51C0(rideIndex); + return 0; + } + + if (goingToBeOpen && isApplying) { + sub_6B5952(rideIndex); + ride->lifecycle_flags |= RIDE_LIFECYCLE_EVER_BEEN_OPENED; + } + + // z = ride->station_heights[i] * 8; + trackElement.x = (ride->station_starts[stationIndex] & 0xFF) * 32; + trackElement.y = (ride->station_starts[stationIndex] >> 8) * 32; + trackElement.element = loc_6B4F6B(rideIndex, trackElement.x, trackElement.y); + if (trackElement.element == NULL) { + // Maze is strange, station start is 0... investigation required + if (ride->type != RIDE_TYPE_MAZE) + return 0; + } + + if ( + ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER || + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT || + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) { + if (ride_find_track_gap(&trackElement, &problematicTrackElement) && (!gConfigGeneral.test_unfinished_tracks || + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; + loc_6B528A(&problematicTrackElement); + return 0; + } + } + + if ( + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) { + if (!ride_check_block_brakes(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + + if (ride->subtype != 255) { + rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); + if (rideType->flags & RIDE_ENTRY_FLAG_1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (ride_check_track_suitability_a(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + if (rideType->flags & RIDE_ENTRY_FLAG_2) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (ride_check_track_suitability_b(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + } + + if (ride->mode == RIDE_MODE_STATION_TO_STATION) { + if (!ride_find_track_gap(&trackElement, &problematicTrackElement)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_STATION_NOT_LONG_ENOUGH; + if (ride_check_station_length(&trackElement, &problematicTrackElement)) { + + // This is to prevent a bug in the check_station_length function + // remove when check_station_length is reveresed and fixed. Prevents + // null dereference. Does not prevent moving screen to top left corner. + if (map_element_get_type(problematicTrackElement.element) != MAP_ELEMENT_TYPE_TRACK) + loc_6B528A(&trackElement); + else loc_6B528A(&problematicTrackElement); + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + if (ride_check_start_and_end_is_station(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + + if (isApplying) + sub_6B4D26(rideIndex, &trackElement); + + if ( + !ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13) && + !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) + ) { + if (sub_6DD84C(ride, rideIndex, &trackElement, isApplying)) + return 0; + } + + if ( + (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint32) & 0x400) && + (ride->lifecycle_flags & RIDE_LIFECYCLE_16) && + !(ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) + ) { + if (sub_6DF4D4(ride, &trackElement, isApplying)) + return 0; + } + + return 1; +} +/** + * + * rct2: 0x006B4EEA + */ +int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) +{ + int stationIndex; + rct_ride *ride; + rct_xy_element trackElement, problematicTrackElement; + + ride = GET_RIDE(rideIndex); + + window_close_by_class(WC_RIDE_CONSTRUCTION); + + stationIndex = ride_mode_check_station_present(ride); + if (stationIndex == -1)return 0; + + if (!ride_mode_check_valid_station_numbers(ride)) + return 0; + + if (!ride_check_for_entrance_exit(rideIndex)) { + loc_6B51C0(rideIndex); + return 0; + } + + if (goingToBeOpen && isApplying) { + sub_6B5952(rideIndex); + ride->lifecycle_flags |= RIDE_LIFECYCLE_EVER_BEEN_OPENED; + } + + // z = ride->station_heights[i] * 8; + trackElement.x = (ride->station_starts[stationIndex] & 0xFF) * 32; + trackElement.y = (ride->station_starts[stationIndex] >> 8) * 32; + trackElement.element = loc_6B4F6B(rideIndex, trackElement.x, trackElement.y); + if (trackElement.element == NULL) { + // Maze is strange, station start is 0... investigation required + if (ride->type != RIDE_TYPE_MAZE) + return 0; + } + + if ( + ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER || + ride->mode == RIDE_MODE_RACE || + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT || + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) { + if (ride_find_track_gap(&trackElement, &problematicTrackElement)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; + loc_6B528A(&problematicTrackElement); + return 0; + } + } + + if ( + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) { + if (!ride_check_block_brakes(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + + if (ride->subtype != 255) { + rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); + if (rideType->flags & RIDE_ENTRY_FLAG_1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (ride_check_track_suitability_a(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + if (rideType->flags & RIDE_ENTRY_FLAG_2) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (ride_check_track_suitability_b(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + } + + if (ride->mode == RIDE_MODE_STATION_TO_STATION) { + if (!ride_find_track_gap(&trackElement, &problematicTrackElement)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_STATION_NOT_LONG_ENOUGH; + if (ride_check_station_length(&trackElement, &problematicTrackElement)) { + + // This is to prevent a bug in the check_station_length function + // remove when check_station_length is reveresed and fixed. Prevents + // null dereference. Does not prevent moving screen to top left corner. + if (map_element_get_type(problematicTrackElement.element) != MAP_ELEMENT_TYPE_TRACK) + loc_6B528A(&trackElement); + else loc_6B528A(&problematicTrackElement); + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + if (ride_check_start_and_end_is_station(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); + return 0; + } + } + + if (isApplying) + sub_6B4D26(rideIndex, &trackElement); + + if ( + !ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13) && + !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) + ) { + if (sub_6DD84C(ride, rideIndex, &trackElement, isApplying)) + return 0; + } + + if ( + (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint32) & 0x400) && + (ride->lifecycle_flags & RIDE_LIFECYCLE_16) && + !(ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) + ) { + if (sub_6DF4D4(ride, &trackElement, isApplying)) + return 0; + } + + return 1; +} + +void ride_set_status(int rideIndex, int status) +{ + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, rideIndex | (status << 8), GAME_COMMAND_SET_RIDE_STATUS, 0, 0); +} + +/** + * + * rct2: 0x006B4EA6 + */ +void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + int rideIndex, targetStatus; + rct_ride *ride; + + rideIndex = *edx & 0xFF; + targetStatus = (*edx >> 8) & 0xFF; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 4; + + ride = GET_RIDE(rideIndex); + RCT2_GLOBAL(0x00F43484, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32); + + switch (targetStatus) { + case RIDE_STATUS_CLOSED: + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + if (ride->status == targetStatus) { + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride_clear_for_construction(rideIndex); + ride_remove_peeps(rideIndex); + } + } + + ride->status = RIDE_STATUS_CLOSED; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; + ride->race_winner = 0xFFFF; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, rideIndex); + } + *ebx = 0; + return; + case RIDE_STATUS_TESTING: + case RIDE_STATUS_OPEN: + if (ride->status == targetStatus) { + *ebx = 0; + return; + } + + if (targetStatus == RIDE_STATUS_TESTING) { + if (!ride_is_valid_for_test(rideIndex, targetStatus == RIDE_STATUS_OPEN, *ebx & GAME_COMMAND_FLAG_APPLY)) { + *ebx = MONEY32_UNDEFINED; + return; + } + } + else if (!ride_is_valid_for_open(rideIndex, targetStatus == RIDE_STATUS_OPEN, *ebx & GAME_COMMAND_FLAG_APPLY)) { + *ebx = MONEY32_UNDEFINED; + return; + } + + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + ride->race_winner = 0xFFFF; + ride->status = targetStatus; + ride_get_measurement(rideIndex, NULL); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + window_invalidate_by_number(WC_RIDE, rideIndex); + } + *ebx = 0; + return; + } +} + +void ride_set_name(int rideIndex, const char *name) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_RENAME_RIDE_ATTRACTION; + game_do_command(1, (rideIndex << 8) | 1, 0, *((int*)(name + 0)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(name + 8)), *((int*)(name + 4))); + game_do_command(2, (rideIndex << 8) | 1, 0, *((int*)(name + 12)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(name + 20)), *((int*)(name + 16))); + game_do_command(0, (rideIndex << 8) | 1, 0, *((int*)(name + 24)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(name + 32)), *((int*)(name + 28))); +} + +/** + * + * rct2: 0x006B578B + */ +void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + rct_window *w; + rct_ride *ride; + rct_string_id newUserStringId; + char oldName[128]; + static char newName[128]; + + int rideIndex = (*ebx >> 8) & 0xFF; + int nameChunkIndex = *eax & 0xFFFF; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + int nameChunkOffset = nameChunkIndex - 1; + if (nameChunkOffset < 0) + nameChunkOffset = 2; + nameChunkOffset *= 12; + RCT2_GLOBAL(newName + nameChunkOffset + 0, uint32) = *edx; + RCT2_GLOBAL(newName + nameChunkOffset + 4, uint32) = *ebp; + RCT2_GLOBAL(newName + nameChunkOffset + 8, uint32) = *edi; + } + + if (nameChunkIndex != 0) { + *ebx = 0; + return; + } + + ride = GET_RIDE(rideIndex); + format_string(oldName, ride->name, &ride->name_arguments); + if (strcmp(oldName, newName) == 0) { + *ebx = 0; + return; + } + + if (newName[0] == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_INVALID_RIDE_ATTRACTION_NAME; + *ebx = MONEY32_UNDEFINED; + return; + } + + newUserStringId = user_string_allocate(4, newName); + if (newUserStringId == 0) { + *ebx = MONEY32_UNDEFINED; + return; + } + + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + // Free the old ride name + user_string_free(ride->name); + + ride->name = newUserStringId; + + gfx_invalidate_screen(); + + // Force ride list window refresh + w = window_find_by_class(WC_RIDE_LIST); + if (w != NULL) + w->no_list_items = 0; + } else { + user_string_free(newUserStringId); + } + + *ebx = 0; +} + +/** + * + * rct2: 0x006CB7FB + */ +int ride_get_refund_price(int ride_id) +{ + uint8 oldpaused = RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = 0; + RCT2_GLOBAL(0x00F4413A, int) = 0; + for(int x = 0; x < 8192; x += 32){ + for(int y = 0; y < 8192; y += 32){ + int tile_idx = ((y * 256) + x) / 32; + rct_map_element* map_element = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[tile_idx]; + do{ + if((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_TRACK && map_element->properties.track.ride_index == ride_id){ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) << 8) | 0x01; + ecx = y; + edx = map_element->properties.track.type; + edi = map_element->base_height * 8; + if(map_element->properties.track.type == 101){ + edx = 2 << 8 | map_element->properties.track.ride_index; + int oldeax = eax; + int oldebx = ebx; + int oldecx = ecx; + int oldedx = edx; + + ebx = oldebx; + ebx |= 0 << 0; + RCT2_GLOBAL(0x00F4413A, int) += game_do_command_p(GAME_COMMAND_38, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + ebx = oldebx; + ebx |= 1 << 8; + ecx = oldecx; + ecx += 16; + edx = oldedx; + RCT2_GLOBAL(0x00F4413A, int) += game_do_command_p(GAME_COMMAND_38, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + ebx = oldebx; + ebx |= 2 << 8; + eax = oldeax; + eax += 16; + ecx = oldecx; + ecx += 16; + edx = oldedx; + RCT2_GLOBAL(0x00F4413A, int) += game_do_command_p(GAME_COMMAND_38, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + ebx = oldebx; + ebx |= 3 << 8; + eax = oldeax; + eax += 16; + ecx = oldecx; + edx = oldedx; + RCT2_GLOBAL(0x00F4413A, int) += game_do_command_p(GAME_COMMAND_38, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + }else{ + edx |= 0xFF << 8; + edx &= ((map_element->properties.track.sequence & 0xF) << 8) | 0xFF; + RCT2_GLOBAL(0x00F4413A, int) += game_do_command_p(GAME_COMMAND_4, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + } + y -= 32; + break; + } + map_element++; + }while(!((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } + } + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = oldpaused; + return RCT2_GLOBAL(0x00F4413A, int); +} + +/** + * + * rct2: 0x006B49D9 + */ +void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + uint8 ride_id = *(uint8*)edx; + + RCT2_GLOBAL(0x009DEA5E, uint16) = 0; + RCT2_GLOBAL(0x009DEA60, uint16) = 0; + RCT2_GLOBAL(0x009DEA62, uint16) = 0; + rct_ride *ride = &g_ride_list[ride_id]; + int x = 0, y = 0, z = 0; + if(ride->overall_view != (uint16)-1){ + x = ((ride->overall_view & 0xFF) * 32) + 16; + y = ((ride->overall_view >> 8) * 32) + 16; + z = map_element_height(x, y); + RCT2_GLOBAL(0x009DEA5E, uint16) = x; + RCT2_GLOBAL(0x009DEA60, uint16) = y; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + } + if(!(*ebx & 0x40) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) && !gConfigCheat.build_in_pause_mode){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + }else{ + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + if(!(*ebx & 8)){ + window_close_by_number(WC_RIDE_CONSTRUCTION, ride_id); + } + window_close_by_number(WC_RIDE, ride_id); + window_close_by_number(WC_DEMOLISH_RIDE_PROMPT, ride_id); + window_close_by_class(WC_NEW_CAMPAIGN); + if(RCT2_GLOBAL(0x01358103, uint8) && ride_id == RCT2_GLOBAL(0x01358117, uint8)){ + RCT2_GLOBAL(0x01358103, uint8) = 0; + } + if(RCT2_GLOBAL(0x01358107, uint8) && ride_id == RCT2_GLOBAL(0x0135811B, uint8)){ + RCT2_GLOBAL(0x01358107, uint8) = 0; + } + ride_clear_for_construction(ride_id); + ride_remove_peeps(ride_id); + RCT2_CALLPROC_X(0x00696707, 0, 0, 0, ride_id, 0, 0, 0); + *ebx = ride_get_refund_price(ride_id); + + RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, ride_id, 0, 0, 0); + news_item_disable_news(NEWS_ITEM_RIDE, ride_id); + + for(int i = 0; i < MAX_BANNERS; i++){ + rct_banner *banner = &gBanners[i]; + if(banner->type != BANNER_NULL && banner->flags & BANNER_FLAG_2 && banner->colour == ride_id){ + banner->flags &= 0xFB; + banner->string_idx = 778; + } + } + + uint16 spriteIndex; + rct_peep *peep; + FOR_ALL_GUESTS(spriteIndex, peep){ + uint8 ride_id_bit = ride_id & 0x3; + uint8 ride_id_offset = ride_id / 8; + peep->rides_been_on[ride_id_offset] &= ~(1 << ride_id_bit); // clear ride from potentially being in rides_been_on + if(peep->state == PEEP_STATE_WATCHING){ + if(peep->current_ride == ride_id){ + peep->current_ride = MAX_RIDES; + if(peep->time_to_stand >= 50){ // make peep stop watching the ride + peep->time_to_stand = 50; + } + } + } + // remove any free voucher for this ride from peep + if(peep->item_standard_flags & PEEP_ITEM_VOUCHER){ + if(peep->voucher_type == VOUCHER_TYPE_RIDE_FREE && peep->voucher_arguments == ride_id){ + peep->item_standard_flags &= ~(PEEP_ITEM_VOUCHER); + } + } + // remove any photos of this ride from peep + if(peep->item_standard_flags & PEEP_ITEM_PHOTO){ + if(peep->photo1_ride_ref == ride_id){ + peep->item_standard_flags &= ~PEEP_ITEM_PHOTO; + } + } + if(peep->item_extra_flags && PEEP_ITEM_PHOTO2){ + if(peep->photo2_ride_ref == ride_id){ + peep->item_extra_flags &= ~PEEP_ITEM_PHOTO2; + } + } + if(peep->item_extra_flags && PEEP_ITEM_PHOTO3){ + if(peep->photo3_ride_ref == ride_id){ + peep->item_extra_flags &= ~PEEP_ITEM_PHOTO3; + } + } + if(peep->item_extra_flags && PEEP_ITEM_PHOTO4){ + if(peep->photo4_ride_ref == ride_id){ + peep->item_extra_flags &= ~PEEP_ITEM_PHOTO4; + } + } + if(peep->guest_heading_to_ride_id == ride_id){ + peep->guest_heading_to_ride_id = MAX_RIDES; + } + if(peep->favourite_ride == ride_id){ + peep->favourite_ride = MAX_RIDES; + } + for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) { + if(peep->thoughts[i].item == ride_id){ + // Clear top thought, push others up + memmove(&peep->thoughts[i], &peep->thoughts[i + 1], sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1)); + peep->thoughts[PEEP_MAX_THOUGHTS - 1].type = PEEP_THOUGHT_TYPE_NONE; + } + } + } + + user_string_free(ride->name); + ride->type = RIDE_TYPE_NULL; + window_invalidate_by_class(WC_RIDE_LIST); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32) = calculate_park_value(); + RCT2_GLOBAL(0x009DEA5E, uint16) = x; + RCT2_GLOBAL(0x009DEA60, uint16) = y; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + return; + }else{ + *ebx = 0; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + return; + } + } +} + +/** + * + * rct2: 0x006B2FC5 + */ +void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + uint8 ride_id = *edx; + uint8 type = *ebx >> 8; + uint8 value = *edx >> 8; + int index = *edi; + rct_ride *ride = &g_ride_list[ride_id]; + switch(type){ + case 0: + ride->track_colour_main[index] = value; + gfx_invalidate_screen(); + break; + case 1: + ride->track_colour_additional[index] = value; + gfx_invalidate_screen(); + break; + case 2: + *((uint8*)(&ride->vehicle_colours[index])) = value; + RCT2_CALLPROC_X(0x006DE102, 0, 0, 0, ride_id, 0, 0, 0); + break; + case 3: + *((uint8*)(&ride->vehicle_colours[index]) + 1) = value; + RCT2_CALLPROC_X(0x006DE102, 0, 0, 0, ride_id, 0, 0, 0); + break; + case 4: + ride->track_colour_supports[index] = value; + gfx_invalidate_screen(); + break; + case 5: + ride->colour_scheme_type &= ~(RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN | RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR); + ride->colour_scheme_type |= value; + for(int i = 1; i < countof(ride->vehicle_colours); i++){ + ride->vehicle_colours[i] = ride->vehicle_colours[0]; + ride->vehicle_colours_extended[i] = ride->vehicle_colours_extended[0]; + } + RCT2_CALLPROC_X(0x006DE102, 0, 0, 0, ride_id, 0, 0, 0); + break; + case 6: + ride->entrance_style = value; + RCT2_GLOBAL(0x01358840, uint8) = value; + gfx_invalidate_screen(); + break; + case 7: + ride->vehicle_colours_extended[index] = value; + RCT2_CALLPROC_X(0x006DE102, 0, 0, 0, ride_id, 0, 0, 0); + break; + } + window_invalidate_by_number(WC_RIDE, ride_id); + } + *ebx = 0; +} + +/** + * + * rct2: 0x006B53E9 + */ +void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + uint32 flags, shop_item; + uint8 ride_number; + money16 price; + rct_ride *ride; + rct_ride_type *ride_type; + bool secondary_price; + + flags = *ebx; + ride_number = (*edx & 0xFF); + ride = GET_RIDE(ride_number); + ride_type = gRideTypeList[ride->subtype]; + price = *edi; + secondary_price = (*edx >> 8); + + //eax + //ebx flags + //ecx ecx + //edx ride_number + //ebp ride_type + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 0x14; + if (flags & 0x1) { + if (!secondary_price) { + shop_item = 0x1F; + if (ride->type != RIDE_TYPE_TOILETS) { + shop_item = ride_type->shop_item; + if (shop_item == 0xFF) { + ride->price = price; + window_invalidate_by_class(WC_RIDE); + return; + } + } + // Check same price in park flags + if ((shop_item < 32 ? RCT2_GLOBAL(0x01358838, uint32) & (1 << shop_item) : RCT2_GLOBAL(0x0135934C, uint32) & (1 << (shop_item - 32))) == 0) { + ride->price = price; + window_invalidate_by_class(WC_RIDE); + return; + } + } + else { + shop_item = ride_type->shop_item_secondary; + if (shop_item == 0xFF) { + shop_item = RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8); + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) == 0) { + ride->price_secondary = price; + window_invalidate_by_class(WC_RIDE); + return; + } + } + // Check same price in park flags + if ((shop_item < 32 ? RCT2_GLOBAL(0x01358838, uint32) & (1 << shop_item) : RCT2_GLOBAL(0x0135934C, uint32) & (1 << (shop_item - 32))) == 0) { + ride->price_secondary = price; + window_invalidate_by_class(WC_RIDE); + return; + } + } + ride = GET_RIDE(0); + ride_type = gRideTypeList[ride->subtype]; + uint8 count = 0; + while (count < 0xFF) { + if (ride->type != 0xFF) { + if (ride->type != RIDE_TYPE_TOILETS || shop_item != 0x1F) { + if (ride_type->shop_item == shop_item) { + ride->price = price; + window_invalidate_by_number(WC_RIDE, count); + } + } + else { + ride->price = price; + window_invalidate_by_number(WC_RIDE, count); + } + // If the shop item is the same or an on-ride photo + if (ride_type->shop_item_secondary == shop_item || + (ride_type->shop_item_secondary == 0xFF && + (shop_item == 0x3 || shop_item == 0x20 || shop_item == 0x21 || shop_item == 0x22))) { + + ride->price_secondary = price; + window_invalidate_by_number(WC_RIDE, count); + } + } + count++; + ride++; + ride_type = gRideTypeList[ride->subtype]; + } + } +} + +bool ride_type_has_flag(int rideType, int flag) +{ + return (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (rideType * 8), uint32) & flag) != 0; +} + +/* + * The next six functions are helpers to access ride data at the offset 10E & + * 110. We believe it stores three distinct values in the following format: + * + * unknown1: bits 9-11 + * unknown2: bits 6-8 + * unknown3: low 5 bits + */ + +int get_var_10E_unk_1(rct_ride* ride) { + return (ride->var_10E >> 8) & 0x7; +} + +int get_var_10E_unk_2(rct_ride* ride) { + return (ride->var_10E >> 5) & 0x7; +} + +int get_var_10E_unk_3(rct_ride* ride) { + return ride->var_10E & 0x1F; +} + +int get_var_110_unk_1(rct_ride* ride) { + return (ride->var_110 >> 8) & 0x7; +} + +int get_var_110_unk_2(rct_ride* ride) { + return (ride->var_110 >> 5) & 0x7; +} + +int get_var_110_unk_3(rct_ride* ride) { + return ride->var_110 & 0x1F; +} + +int get_var_112_unk_1(rct_ride* ride) { + return (ride->var_112 >> 11) & 0x3F; +} + +int get_var_112_unk_2(rct_ride* ride) { + return (ride->var_112 >> 8) & 7; +} + +int get_var_112_unk_3(rct_ride* ride) { + return (ride->var_112 >> 5) & 7; +} + +int get_var_112_unk_4(rct_ride* ride) { + return ride->var_112 & 0x1F; +} + +bool ride_has_spinning_tunnel(rct_ride *ride) { + return ride->special_track_elements & RIDE_ELEMENT_TUNNEL_SPLASH_OR_RAPIDS; +} + +bool ride_has_water_splash(rct_ride *ride) { + return ride->special_track_elements & RIDE_ELEMENT_TUNNEL_SPLASH_OR_RAPIDS; +} + +bool ride_has_rapids(rct_ride *ride) { + return ride->special_track_elements & RIDE_ELEMENT_TUNNEL_SPLASH_OR_RAPIDS; +} + +bool ride_has_log_reverser(rct_ride *ride) { + return ride->special_track_elements & RIDE_ELEMENT_REVERSER_OR_WATERFALL; +} + +bool ride_has_waterfall(rct_ride *ride) { + return ride->special_track_elements & RIDE_ELEMENT_REVERSER_OR_WATERFALL; +} + +bool ride_has_whirlpool(rct_ride *ride) { + return ride->special_track_elements & RIDE_ELEMENT_WHIRLPOOL; +} + +uint8 ride_get_helix_sections(rct_ride *ride) { + // Helix sections stored in the low 5 bits. + return ride->special_track_elements & 0x1F; +} + +bool ride_is_powered_launched(rct_ride *ride) +{ + return + ride->mode == RIDE_MODE_POWERED_LAUNCH_PASSTROUGH || + ride->mode == RIDE_MODE_POWERED_LAUNCH || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED; +} + +bool ride_has_any_track_elements(int rideIndex) +{ + map_element_iterator it; + + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) { + if (map_element_get_type(it.element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (it.element->properties.track.ride_index != rideIndex) + continue; + if (it.element->flags & MAP_ELEMENT_FLAG_GHOST) + continue; + + return true; + } + + return false; +} + +void ride_all_has_any_track_elements(bool *rideIndexArray) +{ + map_element_iterator it; + + memset(rideIndexArray, 0, MAX_RIDES * sizeof(bool)); + + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) { + if (map_element_get_type(it.element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (it.element->flags & MAP_ELEMENT_FLAG_GHOST) + continue; + + rideIndexArray[it.element->properties.track.ride_index] = true; + } +} \ No newline at end of file diff --git a/src/ride/ride.h b/src/ride/ride.h index 8bfe4dcea9..1916962a35 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -24,6 +24,7 @@ #include "../common.h" #include "../peep/peep.h" #include "../world/map.h" +#include "vehicle.h" typedef fixed16_2dp ride_rating; @@ -46,33 +47,84 @@ typedef struct { uint8 entry_index; } ride_list_item; +/** + * Ride type vehicle structure. + * size: 0x65 + */ +typedef struct{ + uint16 var_00; // 0x00 , 0x1A + uint8 var_02; // 0x02 , 0x1C + uint8 var_03; // 0x03 , 0x1D + uint32 var_04; // 0x04 , 0x1E + uint16 var_08; // 0x08 , 0x22 + sint8 var_0A; // 0x0A , 0x24 + uint8 pad_0B; + uint16 var_0C; // 0x0C , 0x26 + uint8 var_0E; // 0x0E , 0x28 + uint8 var_0F; // 0x0F , 0x29 + uint8 var_10; // 0x10 , 0x2A + uint8 var_11; // 0x11 , 0x2B + uint16 var_12; // 0x12 , 0x2C + uint16 var_14; // 0x14 , 0x2E + uint16 var_16; // 0x16 , 0x30 + uint32 base_image_id; // 0x18 , 0x32 + uint32 var_1C; // 0x1C , 0x36 + uint32 var_20; // 0x20 , 0x3A + uint32 var_24; // 0x24 , 0x3E + uint32 var_28; // 0x28 , 0x42 + uint32 var_2C; // 0x2C , 0x46 + uint32 var_30; // 0x30 , 0x4A + uint32 var_34; // 0x34 , 0x4E + uint32 var_38; // 0x38 , 0x52 + uint32 var_3C; // 0x3C , 0x56 + uint32 var_40; // 0x40 , 0x5A + uint32 var_44; // 0x44 , 0x5E + uint32 var_48; // 0x48 , 0x62 + uint32 var_4C; // 0x4C , 0x66 + uint32 no_vehicle_images; // 0x50 , 0x6A + uint8 no_seating_rows; // 0x54 , 0x6E + uint8 pad_55[0x5]; + uint8 var_5A; // 0x5A , 0x74 + uint8 pad_5B; // 0x5B , 0x75 + uint8 var_5C; // 0x5C , 0x76 + uint8 var_5D; // 0x5D , 0x77 + uint8 pad_5E[0x2]; + uint8 var_60; // 0x60 , 0x7A + sint8* peep_loading_positions; // 0x61 , 0x7B +} rct_ride_type_vehicle; + /** * Ride type structure. * size: unknown */ typedef struct { - rct_string_id name; // 0x000 - rct_string_id description; // 0x002 - uint32 var_004; - uint32 var_008; - uint8 var_00C; - uint8 var_00D; - uint8 var_00E; - uint8 var_00F; - uint8 var_010; - uint8 var_011; - uint8 var_012; - uint8 var_013; - uint8 pad_014[0x19E]; - sint8 excitement_multipler; // 0x1B2 - sint8 intensity_multipler; // 0x1B3 - sint8 nausea_multipler; // 0x1B4 - uint8 pad_1B5; - uint32 var_1B6; - uint8 pad_1BA[0x04]; - uint8 category[2]; // 0x1BE - uint8 shop_item; // 0x1C0 - uint8 shop_item_secondary; // 0x1C1 + rct_string_id name; // 0x000 + rct_string_id description; // 0x002 + uint32 images_offset; // 0x004 + uint32 flags; // 0x008 + uint8 ride_type[3]; // 0x00C + uint8 min_cars_in_train; // 0x00F + uint8 max_cars_in_train; // 0x010 + uint8 cars_per_flat_ride; // 0x011 + uint8 zero_cars; // 0x012 + uint8 tab_vehicle; // 0x013 + uint8 default_vehicle; // 0x014 + uint8 front_vehicle; // 0x015 + uint8 second_vehicle; // 0x016 + uint8 rear_vehicle; // 0x017 + uint8 third_vehicle; // 0x018 + uint8 pad_019; + rct_ride_type_vehicle vehicles[4]; // 0x1A + uint32 var_1AE; + sint8 excitement_multipler; // 0x1B2 + sint8 intensity_multipler; // 0x1B3 + sint8 nausea_multipler; // 0x1B4 + uint8 max_height; // 0x1B5 + uint32 enabledTrackPieces; // 0x1B6 + uint32 enabledTrackPiecesAdditional; // 0x1BA + uint8 category[2]; // 0x1BE + uint8 shop_item; // 0x1C0 + uint8 shop_item_secondary; // 0x1C1 } rct_ride_type; /** @@ -87,7 +139,7 @@ typedef struct { uint16 pad_002; uint8 mode; // 0x004 uint8 colour_scheme_type; // 0x005 - uint16 vehicle_colours[32]; // 0x006 + rct_vehicle_colour vehicle_colours[32]; // 0x006 uint8 pad_046[0x03]; // 0 = closed, 1 = open, 2 = test uint8 status; // 0x049 @@ -101,7 +153,8 @@ typedef struct { uint8 var_066[4]; uint16 entrances[4]; // 0x06A uint16 exits[4]; // 0x072 - uint8 pad_07A[0x0C]; + uint16 first_peep_in_queue[4]; // 0x07A + uint8 pad_082[4]; uint16 vehicles[32]; // 0x086 Points to the first car in the train uint8 depart_flags; // 0x0C6 @@ -115,17 +168,26 @@ typedef struct { uint8 min_waiting_time; // 0x0CE uint8 max_waiting_time; // 0x0CF union { - uint8 var_0D0; + uint8 operation_option; // 0x0D0 uint8 time_limit; // 0x0D0 uint8 num_laps; // 0x0D0 + uint8 launch_speed; // 0x0D0 + uint8 speed; // 0x0D0 + uint8 rotations; // 0x0D0 }; uint8 pad_0D1[0x3]; uint8 measurement_index; // 0x0D4 - uint8 var_0D5; - uint8 pad_0D6[0x2]; + // bits 0 through 4 are the number of helix sections + // bit 5: spinning tunnel, water splash, or rapids + // bit 6: log reverser, waterfall + // bit 7: whirlpool + uint8 special_track_elements; // 0x0D5 + uint8 pad_0D6[2]; + // Divide this value by 29127 to get the human-readable max speed + // (in RCT2, display_speed = (max_speed * 9) >> 18) sint32 max_speed; // 0x0D8 sint32 average_speed; // 0x0DC - uint8 pad_0E0[0x4]; + uint8 pad_0E0[4]; sint32 length[4]; // 0x0E4 uint16 time[4]; // 0x0F4 fixed16_2dp max_positive_vertical_g; // 0x0FC @@ -142,9 +204,9 @@ typedef struct { uint8 drops; // 0x115 (??XX XXXX) uint8 pad_116; uint8 highest_drop_height; // 0x117 - uint32 var_118; - uint8 pad_11C[0x02]; - uint8 var_11E; + sint32 sheltered_length; // 0x118 + uint8 pad_11C[0x2]; + uint8 num_sheltered_sections; // 0x11E uint8 var_11F; sint16 var_120; sint16 var_122; @@ -171,16 +233,19 @@ typedef struct { ride_rating nausea; // 0x144 }; }; - uint16 reliability; // 0x146 + uint16 value; // 0x146 uint16 var_148; - uint16 var_14A; - uint8 pad_14C; - uint8 var_14D; + uint8 satisfaction; // 0x14A + uint8 satisfaction_time_out; // 0x14B + uint8 satisfaction_next; // 0x14C + // Various flags stating whether a window needs to be refreshed + uint8 window_invalidate_flags; // 0x14D uint8 pad_14E[0x02]; uint32 total_customers; // 0x150 money32 total_profit; // 0x154 - uint16 var_158; - uint8 pad_15A; + uint8 popularity; // 0x158 + uint8 popularity_time_out; // 0x159 Updated every purchase and ?possibly by time? + uint8 popularity_next; // 0x15A When timeout reached this will be the next popularity uint8 num_riders; // 0x15B uint8 music_tune_id; // 0x15C uint8 var_15D; @@ -188,7 +253,9 @@ typedef struct { uint16 slide_peep; // 0x15E uint16 maze_tiles; // 0x15E }; - uint8 pad_160[0x16]; + uint8 pad_160[0xE]; + uint8 slide_peep_t_shirt_colour;// 0x16E + uint8 pad_16F[0x7]; uint8 var_176; uint8 pad_177[0x9]; sint16 build_date; // 0x180 @@ -204,10 +271,14 @@ typedef struct { uint8 broken_car; // 0x192 uint8 breakdown_reason; // 0x193 money16 price_secondary; // 0x194 - uint16 var_196; - // used in computing excitement, nausea, etc - uint8 var_198; - uint8 var_199; + // Starts at RIDE_INITIAL_RELIABILITY and decreases from there. Right shift + // this number by 8 to get a reliability percentage 0-100 + uint16 reliability; // 0x196 + // Small constant used to increase the unreliability as the game continues, + // making breakdowns more and more likely. + uint8 unreliability_factor; // 0x198 + // Range from [0, 100] + uint8 downtime; // 0x199 uint8 inspection_interval; // 0x19A uint8 last_inspection; // 0x19B uint8 var_19C; @@ -218,8 +289,8 @@ typedef struct { uint8 var_1A1; uint8 var_1A2; uint8 var_1A3; - uint32 var_1A4; - uint8 pad_1A8[4]; + uint32 no_primary_items_sold; // 0x1A4 + uint32 no_secondary_items_sold; // 0x1A8 uint8 var_1AC; uint8 var_1AD; uint8 var_1AE; @@ -260,7 +331,7 @@ typedef struct { uint16 num_items; // 0x0006 uint16 current_item; // 0x0008 uint8 vehicle_index; // 0x000A - uint8 var_0B; + uint8 current_station; // 0x000B sint8 vertical[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x000C sint8 lateral[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x12CC uint8 velocity[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x258C @@ -291,9 +362,49 @@ enum { RIDE_LIFECYCLE_MUSIC = 1 << 13, RIDE_LIFECYCLE_INDESTRUCTIBLE = 1 << 14, RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK = 1 << 15, - + RIDE_LIFECYCLE_16 = 1 << 16, RIDE_LIFECYCLE_CABLE_LIFT = 1 << 17, - RIDE_LIFECYCLE_19 = 1 << 19 + RIDE_LIFECYCLE_18 = 1 << 18, + RIDE_LIFECYCLE_SIX_FLAGS = 1 << 19, + + // Used to bring up the "real" ride window after a crash. Can be removed once vehicle_update is decompiled + RIDE_LIFECYCLE_CRASHED_WINDOW_OPENED = 1 << 20 +}; + +// Constants used by the ride_type->flags property at 0x008 +enum { + RIDE_ENTRY_FLAG_0 = 1 << 0, // 0x1 + RIDE_ENTRY_FLAG_1 = 1 << 1, // 0x2 + RIDE_ENTRY_FLAG_2 = 1 << 2, // 0x4 + RIDE_ENTRY_FLAG_3 = 1 << 3, // 0x8 + RIDE_ENTRY_FLAG_4 = 1 << 4, // 0x10 + RIDE_ENTRY_FLAG_5 = 1 << 5, // 0x20 + RIDE_ENTRY_FLAG_6 = 1 << 6, // 0x40 + RIDE_ENTRY_FLAG_7 = 1 << 7, // 0x80 + RIDE_ENTRY_FLAG_8 = 1 << 8, // 0x100 + RIDE_ENTRY_FLAG_9 = 1 << 9, // 0x200 + RIDE_ENTRY_FLAG_COVERED_RIDE = 1 << 10, // 0x400 + RIDE_ENTRY_FLAG_11 = 1 << 11, // 0x800 + RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME = 1 << 12, // 0x1000 + RIDE_ENTRY_FLAG_SEPERATE_RIDE = 1 << 13, // 0x2000 + RIDE_ENTRY_FLAG_14 = 1 << 14, // 0x4000 + RIDE_ENTRY_FLAG_15 = 1 << 15, // 0x8000 + RIDE_ENTRY_FLAG_16 = 1 << 16, // 0x10000 + RIDE_ENTRY_FLAG_17 = 1 << 17, // 0x20000 + RIDE_ENTRY_FLAG_18 = 1 << 18, // 0x40000 + RIDE_ENTRY_FLAG_19 = 1 << 19, // 0x80000 + RIDE_ENTRY_FLAG_20 = 1 << 20, // 0x100000 + RIDE_ENTRY_FLAG_21 = 1 << 21, // 0x200000 + RIDE_ENTRY_FLAG_22 = 1 << 22, // 0x400000 + RIDE_ENTRY_FLAG_23 = 1 << 23, // 0x800000 + RIDE_ENTRY_FLAG_24 = 1 << 24, // 0x1000000 + RIDE_ENTRY_FLAG_25 = 1 << 25, // 0x2000000 + RIDE_ENTRY_FLAG_26 = 1 << 26, // 0x4000000 + RIDE_ENTRY_FLAG_27 = 1 << 27, // 0x8000000 + RIDE_ENTRY_FLAG_28 = 1 << 28, // 0x10000000 + RIDE_ENTRY_FLAG_29 = 1 << 29, // 0x20000000 + RIDE_ENTRY_FLAG_30 = 1 << 30, // 0x40000000 + RIDE_ENTRY_FLAG_31 = 1 << 31, // 0x80000000 }; enum { @@ -306,9 +417,9 @@ enum { RIDE_TYPE_MINIATURE_RAILWAY, RIDE_TYPE_MONORAIL, RIDE_TYPE_MINI_SUSPENDED_COASTER, - RIDE_TYPE_BUMPER_BOATS, + RIDE_TYPE_BOAT_RIDE, RIDE_TYPE_WOODEN_WILD_MOUSE, - RIDE_TYPE_STEEPLECHASE, + RIDE_TYPE_STEEPLECHASE = 10, RIDE_TYPE_CAR_RIDE, RIDE_TYPE_LAUNCHED_FREEFALL, RIDE_TYPE_BOBSLEIGH_COASTER, @@ -318,37 +429,37 @@ enum { RIDE_TYPE_MINE_TRAIN_COASTER, RIDE_TYPE_CHAIRLIFT, RIDE_TYPE_CORKSCREW_ROLLER_COASTER, - RIDE_TYPE_MAZE, + RIDE_TYPE_MAZE = 20, RIDE_TYPE_SPIRAL_SLIDE, RIDE_TYPE_GO_KARTS, RIDE_TYPE_LOG_FLUME, RIDE_TYPE_RIVER_RAPIDS, - RIDE_TYPE_BUMPER_CARS, + RIDE_TYPE_DODGEMS, RIDE_TYPE_PIRATE_SHIP, RIDE_TYPE_SWINGING_INVERTER_SHIP, RIDE_TYPE_FOOD_STALL, RIDE_TYPE_1D, - RIDE_TYPE_DRINK_STALL, + RIDE_TYPE_DRINK_STALL = 30, RIDE_TYPE_1F, RIDE_TYPE_SHOP, RIDE_TYPE_MERRY_GO_ROUND, RIDE_TYPE_22, RIDE_TYPE_INFORMATION_KIOSK, - RIDE_TYPE_BATHROOM, + RIDE_TYPE_TOILETS, RIDE_TYPE_FERRIS_WHEEL, RIDE_TYPE_MOTION_SIMULATOR, RIDE_TYPE_3D_CINEMA, - RIDE_TYPE_TOP_SPIN, + RIDE_TYPE_TOP_SPIN = 40, RIDE_TYPE_SPACE_RINGS, RIDE_TYPE_REVERSE_FREEFALL_COASTER, - RIDE_TYPE_ELEVATOR, + RIDE_TYPE_LIFT, RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER, - RIDE_TYPE_ATM, + RIDE_TYPE_CASH_MACHINE, RIDE_TYPE_TWIST, RIDE_TYPE_HAUNTED_HOUSE, RIDE_TYPE_FIRST_AID, RIDE_TYPE_CIRCUS_SHOW, - RIDE_TYPE_GHOST_TRAIN, + RIDE_TYPE_GHOST_TRAIN = 50, RIDE_TYPE_TWISTER_ROLLER_COASTER, RIDE_TYPE_WOODEN_ROLLER_COASTER, RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER, @@ -358,7 +469,7 @@ enum { RIDE_TYPE_FLYING_ROLLER_COASTER, RIDE_TYPE_3A, RIDE_TYPE_VIRGINIA_REEL, - RIDE_TYPE_SPLASH_BOATS, + RIDE_TYPE_SPLASH_BOATS = 60, RIDE_TYPE_MINI_HELICOPTERS, RIDE_TYPE_LAY_DOWN_ROLLER_COASTER, RIDE_TYPE_SUSPENDED_MONORAIL, @@ -368,7 +479,7 @@ enum { RIDE_TYPE_MINI_GOLF, RIDE_TYPE_GIGA_COASTER, RIDE_TYPE_ROTO_DROP, - RIDE_TYPE_FLYING_SAUCERS, + RIDE_TYPE_FLYING_SAUCERS = 70, RIDE_TYPE_CROOKED_HOUSE, RIDE_TYPE_MONORAIL_CYCLES, RIDE_TYPE_COMPACT_INVERTED_COASTER, @@ -378,7 +489,7 @@ enum { RIDE_TYPE_MAGIC_CARPET, RIDE_TYPE_SUBMARINE_RIDE, RIDE_TYPE_RIVER_RAFTS, - RIDE_TYPE_50, + RIDE_TYPE_50 = 80, RIDE_TYPE_ENTERPRISE, RIDE_TYPE_52, RIDE_TYPE_53, @@ -387,8 +498,8 @@ enum { RIDE_TYPE_INVERTED_IMPULSE_COASTER, RIDE_TYPE_MINI_ROLLER_COASTER, RIDE_TYPE_MINE_RIDE, - RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER, - RIDE_TYPE_90 + RIDE_TYPE_59, + RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER = 90 }; enum { @@ -401,7 +512,7 @@ enum { RIDE_MODE_NORMAL, RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, - RIDE_MODE_POWERED_LAUNCH, // RCT1 style? + RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, // RCT2 style, pass through station RIDE_MODE_SHUTTLE, RIDE_MODE_BOAT_HIRE, RIDE_MODE_UPWARD_LAUNCH, @@ -433,7 +544,7 @@ enum { RIDE_MODE_CROOKED_HOUSE, RIDE_MODE_FREEFALL_DROP, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, - RIDE_MODE_POWERED_LAUNCH_35, // RCT2 style? + RIDE_MODE_POWERED_LAUNCH, // RCT1 style, don't pass through station RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED }; @@ -555,6 +666,16 @@ enum { RIDE_INSPECTION_NEVER }; +// Flags used by ride->window_invalidate_flags +enum { + RIDE_INVALIDATE_RIDE_CUSTOMER = 1, + RIDE_INVALIDATE_RIDE_INCOME = 1 << 1, + RIDE_INVALIDATE_RIDE_MAIN = 1 << 2, + RIDE_INVALIDATE_RIDE_LIST = 1 << 3, + RIDE_INVALIDATE_RIDE_OPERATING = 1 << 4, + RIDE_INVALIDATE_RIDE_MAINTENANCE = 1 << 5, +}; + typedef struct { uint8 main; uint8 additional; @@ -573,10 +694,53 @@ enum { RIDE_MEASUREMENT_FLAG_G_FORCES = 1 << 2 }; +// Constants for ride->special_track_elements +enum { + RIDE_ELEMENT_TUNNEL_SPLASH_OR_RAPIDS = 1 << 5, + RIDE_ELEMENT_REVERSER_OR_WATERFALL = 1 << 6, + RIDE_ELEMENT_WHIRLPOOL = 1 << 7 +}; + +enum { + RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_MAIN = 1 << 0, + RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_ADDITIONAL = 1 << 1, + RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_SUPPORTS = 1 << 2, + RIDE_TYPE_FLAG_3 = 1 << 3, + RIDE_TYPE_FLAG_HAS_LEAVE_WHEN_ANOTHER_VEHICLE_ARRIVES_AT_STATION = 1 << 4, + RIDE_TYPE_FLAG_CAN_SYNCHRONISE_ADJACENT_STATIONS = 1 << 5, + RIDE_TYPE_FLAG_6 = 1 << 6, + RIDE_TYPE_FLAG_HAS_G_FORCES = 1 << 7, + RIDE_TYPE_FLAG_8 = 1 << 8, // something to do with track, maybe whether it can have gaps + RIDE_TYPE_FLAG_HAS_DATA_LOGGING = 1 << 9, + RIDE_TYPE_FLAG_HAS_DROPS = 1 << 10, + RIDE_TYPE_FLAG_NO_TEST_MODE = 1 << 11, + RIDE_TYPE_FLAG_12 = 1 << 12, + RIDE_TYPE_FLAG_13 = 1 << 13, // something to do with stations or vehicles + RIDE_TYPE_FLAG_HAS_LOAD_OPTIONS = 1 << 14, + RIDE_TYPE_FLAG_15 = 1 << 15, // something to do with station, price and viewport zoom + RIDE_TYPE_FLAG_16 = 1 << 16, // something to do with vehicle colour scheme + RIDE_TYPE_FLAG_IS_SHOP = 1 << 17, + RIDE_TYPE_FLAG_18 = 1 << 18, + RIDE_TYPE_FLAG_SELLS_FOOD = 1 << 19, + RIDE_TYPE_FLAG_20 = 1 << 20, + RIDE_TYPE_FLAG_21 = 1 << 21, + RIDE_TYPE_FLAG_IN_RIDE = 1 << 22, // peeps are "IN" (ride) rather than "ON" (ride) + RIDE_TYPE_FLAG_23 = 1 << 23, // sells food?, seems to be used for food awards... + RIDE_TYPE_FLAG_SELLS_DRINKS = 1 << 24, + RIDE_TYPE_FLAG_IS_BATHROOM = 1 << 25, + RIDE_TYPE_FLAG_26 = 1 << 26, // something to do with vehicle colours + RIDE_TYPE_FLAG_27 = 1 << 27, + RIDE_TYPE_FLAG_HAS_TRACK = 1 << 28, + RIDE_TYPE_FLAG_29 = 1 << 29, + RIDE_TYPE_FLAG_30 = 1 << 30, + RIDE_TYPE_FLAG_SUPPORTS_MULTIPLE_TRACK_COLOUR = 1 << 31, +}; + #define MAX_RIDES 255 #define MAX_RIDE_MEASUREMENTS 8 -#define RIDE_RELIABILITY_UNDEFINED 0xFFFF +#define RIDE_VALUE_UNDEFINED 0xFFFF +#define RIDE_INITIAL_RELIABILITY ((100 << 8) - 1) #define STATION_DEPART_FLAG (1 << 7) #define STATION_DEPART_MASK (~STATION_DEPART_FLAG) @@ -609,26 +773,71 @@ void reset_all_ride_build_dates(); void ride_update_favourited_stat(); void ride_update_all(); void ride_check_all_reachable(); -rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY); -rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *outX, int *outY); +void ride_update_satisfaction(rct_ride* ride, uint8 happiness); +void ride_update_popularity(rct_ride* ride, uint8 pop_amount); +int sub_6CAF80(int rideIndex, rct_xy_element *output); +int track_get_next(rct_xy_element *input, rct_xy_element *output); +int ride_find_track_gap(rct_xy_element *input, rct_xy_element *output); void ride_construct_new(ride_list_item listItem); -int ride_modify(rct_map_element *trackMapElement, int x, int y); +void ride_construct(int rideIndex); +int ride_modify(rct_xy_element *input); void ride_get_status(int rideIndex, int *formatSecondary, int *argument); rct_peep *ride_get_assigned_mechanic(rct_ride *ride); int ride_get_total_length(rct_ride *ride); +int ride_get_total_time(rct_ride *ride); int ride_can_have_multiple_circuits(rct_ride *ride); track_colour ride_get_track_colour(rct_ride *ride, int colourScheme); vehicle_colour ride_get_vehicle_colour(rct_ride *ride, int vehicleIndex); rct_ride_type *ride_get_entry(rct_ride *ride); uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType); +void reset_type_to_ride_entry_index_map(); void ride_measurement_clear(rct_ride *ride); void ride_measurements_update(); rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message); void ride_breakdown_add_news_item(int rideIndex); rct_peep *ride_find_closest_mechanic(rct_ride *ride, int forInspection); int sub_6CC3FB(int rideIndex); +void sub_6C9627(); +int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element** output_element, uint16 flags); void ride_set_map_tooltip(rct_map_element *mapElement); int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint16 sampleRate, uint32 position, uint8 *tuneId); void ride_music_update_final(); +void ride_prepare_breakdown(int rideIndex, int breakdownReason); +rct_map_element *ride_get_station_start_track_element(rct_ride *ride, int stationIndex); +rct_map_element *ride_get_station_exit_element(rct_ride *ride, int x, int y, int z); +void ride_set_status(int rideIndex, int status); +void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void ride_set_name(int rideIndex, const char *name); +void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +int ride_get_refund_price(int ride_id); +void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); + + +int get_var_10E_unk_1(rct_ride* ride); +int get_var_10E_unk_2(rct_ride* ride); +int get_var_10E_unk_3(rct_ride* ride); +int get_var_110_unk_1(rct_ride* ride); +int get_var_110_unk_2(rct_ride* ride); +int get_var_110_unk_3(rct_ride* ride); +int get_var_112_unk_1(rct_ride* ride); +int get_var_112_unk_2(rct_ride* ride); +int get_var_112_unk_3(rct_ride* ride); +int get_var_112_unk_4(rct_ride* ride); + +uint8 ride_get_helix_sections(rct_ride *ride); +bool ride_has_spinning_tunnel(rct_ride *ride); +bool ride_has_water_splash(rct_ride *ride); +bool ride_has_rapids(rct_ride *ride); +bool ride_has_log_reverser(rct_ride *ride); +bool ride_has_waterfall(rct_ride *ride); +bool ride_has_whirlpool(rct_ride *ride); + +bool ride_type_has_flag(int rideType, int flag); +bool ride_is_powered_launched(rct_ride *ride); +bool ride_has_any_track_elements(int rideIndex); +void ride_all_has_any_track_elements(bool *rideIndexArray); #endif diff --git a/src/ride/ride_data.c b/src/ride/ride_data.c index 5ba1213a73..593eaac1c8 100644 --- a/src/ride/ride_data.c +++ b/src/ride/ride_data.c @@ -678,6 +678,7 @@ const rct_ride_name_convention RideNameConvention[96] = { { 1229, 1243, 1257, 0 } }; +/* rct2: 0x0097C8AC */ const uint8 RideAvailableModes[] = { RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 00 Spiral Roller coaster RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 01 Stand Up Coaster @@ -694,11 +695,11 @@ const uint8 RideAvailableModes[] = { RIDE_MODE_UPWARD_LAUNCH, RIDE_MODE_DOWNWARD_LAUNCH, 0xFF, // 0C Launched Freefall RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 0D Bobsleigh Coaster RIDE_MODE_ROTATING_LIFT, 0xFF, // 0E Observation Tower - RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, RIDE_MODE_POWERED_LAUNCH, 0xFF, // 0F Looping Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, RIDE_MODE_POWERED_LAUNCH, 0xFF, // 0F Looping Roller Coaster RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 10 Dinghy Slide RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 11 Mine Train Coaster RIDE_MODE_STATION_TO_STATION, 0xFF, // 12 Chairlift - RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0x23, 2, 0xFF, // 13 Corkscrew Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, RIDE_MODE_POWERED_LAUNCH, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, 0xFF, // 13 Corkscrew Roller Coaster RIDE_MODE_MAZE, 0xFF, // 14 Maze RIDE_MODE_SINGLE_RIDE_PER_ADMISSION, RIDE_MODE_UNLIMITED_RIDES_PER_ADMISSION, 0xFF, // 15 Spiral Slide RIDE_MODE_RACE, RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 16 Go Karts @@ -752,9 +753,9 @@ const uint8 RideAvailableModes[] = { RIDE_MODE_BUMPERCAR, 0xFF, // 46 Flying Saucers RIDE_MODE_CROOKED_HOUSE, 0xFF, // 47 Crooked House RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 48 Monorail Cycles - RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 2, 0xFF, // 49 Compact Inverted Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, 0xFF, // 49 Compact Inverted Coaster RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 4A Water Coaster - RIDE_MODE_POWERED_LAUNCH, 0xFF, // 4B Air Powered Vertical Coaster + RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, RIDE_MODE_POWERED_LAUNCH, 0xFF, // 4B Air Powered Vertical Coaster RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 4C Inverted Hairpin Coaster RIDE_MODE_SWING, 0xFF, // 4D Magic Carpet RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 4E Submarine Ride @@ -765,11 +766,11 @@ const uint8 RideAvailableModes[] = { RIDE_MODE_SHOP_STALL, 0xFF, // 53 (none) RIDE_MODE_SHOP_STALL, 0xFF, // 54 (none) RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 55 (none) - RIDE_MODE_POWERED_LAUNCH, 0xFF, // 56 Inverted Impulse Coaster + RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, RIDE_MODE_POWERED_LAUNCH, 0xFF, // 56 Inverted Impulse Coaster RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 57 Mini Roller Coaster RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 58 Mine Ride RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 59 LIM Launched Roller Coaster - RIDE_MODE_POWERED_LAUNCH_35, RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED, 0xFF // 60 (none) + RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, RIDE_MODE_POWERED_LAUNCH, RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED, 0xFF // 60 (none) }; const uint8 RideAvailableBreakdowns[] = { @@ -864,4 +865,113 @@ const uint8 RideAvailableBreakdowns[] = { (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 58 Mine Ride (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE), // 59 LIM Launched Roller Coaster (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE) // 60 (none) -}; \ No newline at end of file +}; + +const rct_ride_entrance_definition RideEntranceDefinitions[12] = { + { 22664, 32, 2 }, // RIDE_ENTRANCE_STYLE_PLAIN + { 22760, 31, 21 }, // RIDE_ENTRANCE_STYLE_WOODEN + { 22680, 43, 2 }, // RIDE_ENTRANCE_STYLE_CANVAS_TENT + { 22728, 43, 19 }, // RIDE_ENTRANCE_STYLE_CASTLE_GREY + { 22712, 33, 19 }, // RIDE_ENTRANCE_STYLE_CASTLE_BROWN + { 22776, 32, 19 }, // RIDE_ENTRANCE_STYLE_JUNGLE + { 22744, 32, 20 }, // RIDE_ENTRANCE_STYLE_LOG_CABIN + { 22696, 34, 19 }, // RIDE_ENTRANCE_STYLE_CLASSICAL_ROMAN + { 22792, 40, 22 }, // RIDE_ENTRANCE_STYLE_ABSTRACT + { 22824, 35, 23 }, // RIDE_ENTRANCE_STYLE_SNOW_ICE + { 22840, 33, 19 }, // RIDE_ENTRANCE_STYLE_PAGODA + { 22856, 33, 2 } // RIDE_ENTRANCE_STYLE_SPACE +}; + +// Data read from 0x0097D7C9 4 bytes at a time +const uint8 RideLiftHillAdjustments[0x60] = { + 7, // Spiral Roller coaster + 4, // Stand Up Coaster + 4, // Suspended Swinging + 5, // Inverted + 4, // Steel Mini Coaster + 5, // Mini Railroad + 5, // Monorail + 4, // Mini Suspended Coaster + 5, // Bumper Boats + 4, // Wooden Wild Mine/Mouse + 4, // Steeplechase/Motorbike/Soap Box Derby + 5, // Car Ride + 5, // Launched Freefall + 4, // Bobsleigh Coaster + 5, // Observation Tower + 4, // Looping Roller Coaster + 4, // Dinghy Slide + 4, // Mine Train Coaster + 5, // Chairlift + 4, // Corkscrew Roller Coaster + 5, // Maze + 5, // Spiral Slide + 5, // Go Karts + 5, // Log Flume + 5, // River Rapids + 5, // Bumper Cars + 5, // Pirate Ship + 5, // Swinging Inverter Ship + 5, // Food Stall + 5, // (none) + 5, // Drink Stall + 5, // (none) + 5, // Shop (all types) + 5, // Merry Go Round + 5, // Balloon Stall (maybe) + 5, // Information Kiosk + 5, // Bathroom + 5, // Ferris Wheel + 5, // Motion Simulator + 5, // 3D Cinema + 5, // Gravitron + 5, // Space Rings + 5, // Reverse Freefall Coaster + 5, // Elevator + 4, // Vertical Drop Roller Coaster + 5, // ATM + 5, // Twist + 5, // Haunted House + 5, // First Aid + 5, // Circus Show + 5, // Ghost Train + 5, // Twister Roller Coaster + 5, // Wooden Roller Coaster + 3, // Side-Friction Roller Coaster + 4, // Wild Mouse + 4, // Multi Dimension Coaster + 4, // (none) + 4, // Flying Roller Coaster + 4, // (none) + 3, // Virginia Reel + 5, // Splash Boats + 5, // Mini Helicopters + 4, // Lay-down Roller Coaster + 5, // Suspended Monorail + 4, // (none) + 3, // Reverser Roller Coaster + 4, // Heartline Twister Roller Coaster + 5, // Mini Golf + 5, // Giga Coaster + 5, // Roto-Drop + 5, // Flying Saucers + 5, // Crooked House + 5, // Monorail Cycles + 4, // Compact Inverted Coaster + 4, // Water Coaster + 5, // Air Powered Vertical Coaster + 4, // Inverted Hairpin Coaster + 5, // Magic Carpet + 5, // Submarine Ride + 5, // River Rafts + 5, // (none) + 5, // Enterprise + 5, // (none) + 5, // (none) + 5, // (none) + 4, // (none) + 4, // Inverted Impulse Coaster + 4, // Mini Roller Coaster + 5, // Mine Ride + 4 // LIM Launched Roller Coaster +}; diff --git a/src/ride/ride_data.h b/src/ride/ride_data.h index c2e81cc9f8..f4173d6547 100644 --- a/src/ride/ride_data.h +++ b/src/ride/ride_data.h @@ -30,6 +30,12 @@ typedef struct { rct_string_id unk_name; } rct_ride_name_convention; +typedef struct { + uint32 spriteIndex; + uint16 height; + uint16 var_06; +} rct_ride_entrance_definition; + extern const bool hasRunningTrack[0x60]; extern const uint8 initialUpkeepCosts[0x60]; extern const uint8 costPerTrackPiece[0x60]; @@ -42,4 +48,7 @@ extern const rct_ride_name_convention RideNameConvention[96]; extern const uint8 RideAvailableModes[]; extern const uint8 RideAvailableBreakdowns[]; -#endif \ No newline at end of file +extern const rct_ride_entrance_definition RideEntranceDefinitions[12]; +extern const uint8 RideLiftHillAdjustments[0x60]; + +#endif diff --git a/src/ride/ride_ratings.c b/src/ride/ride_ratings.c index 9a88f57509..ed26aac9d2 100644 --- a/src/ride/ride_ratings.c +++ b/src/ride/ride_ratings.c @@ -49,34 +49,21 @@ static void ride_ratings_update_state_4(); static void ride_ratings_update_state_5(); static void loc_6B5BB2(); static void ride_ratings_calculate(rct_ride *ride); -static void ride_ratings_reliability_calculate(rct_ride *ride); +static void ride_ratings_calculate_value(rct_ride *ride); -static int sub_6C6402(rct_map_element *mapElement, int *x, int *y, int *z) +int sub_6C6402(rct_map_element **mapElement, int *x, int *y, int *z) { int eax, ebx, ecx, edx, esi, edi, ebp; eax = *x; ecx = *y; - esi = (int)mapElement; - RCT2_CALLFUNC_X(0x006C6402, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + esi = (int)*mapElement; + int result = RCT2_CALLFUNC_X(0x006C6402, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); *x = *((uint16*)&eax); *y = *((uint16*)&ecx); *z = *((uint8*)&edx); - return 1; -} - -static int sub_6C60C2(rct_map_element *mapElement, int *x, int *y, int *z) -{ - int eax, ebx, ecx, edx, esi, edi, ebp; - - eax = *x; - ecx = *y; - esi = (int)mapElement; - RCT2_CALLFUNC_X(0x006C6402, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *x = *((uint16*)&eax); - *y = *((uint16*)&ecx); - *z = *((uint8*)&edx); - return 1; + *mapElement = (rct_map_element*)esi; + return result & (0x100); } /** @@ -217,13 +204,13 @@ static void loc_6B5BB2() */ static void ride_ratings_update_state_2() { - // sub_6C6402 returns a carry, CALLFUNC doesn't support this - // so have to wait for sub_6C60C2 to be decompiled + // TODO test this function RCT2_CALLPROC_EBPSAFE(0x006B5C66); return; rct_ride *ride; rct_map_element *mapElement; + rct_xy_element trackElement, nextTrackElement; int x, y, z, trackType, entranceIndex; ride = GET_RIDE(_rideRatingsCurrentRide); @@ -236,11 +223,11 @@ static void ride_ratings_update_state_2() y = RCT2_GLOBAL(0x0138B586, uint16) / 32; z = RCT2_GLOBAL(0x0138B588, uint16) / 8; - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + mapElement = map_get_first_element_at(x, y); trackType = RCT2_GLOBAL(0x0138B592, uint8); do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_TRACK) + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; if (mapElement->base_height != z) continue; @@ -255,13 +242,18 @@ static void ride_ratings_update_state_2() RCT2_CALLPROC_X(0x006B5F9D, 0, 0, 0, 0, (int)mapElement, 0, 0); - x = RCT2_GLOBAL(0x0138B584, uint16); - y = RCT2_GLOBAL(0x0138B586, uint16); - if (!sub_6C60C2(mapElement, &x, &y, &z)) { + trackElement.x = RCT2_GLOBAL(0x0138B584, uint16); + trackElement.y = RCT2_GLOBAL(0x0138B586, uint16); + trackElement.element = mapElement; + if (!track_get_next(&trackElement, &nextTrackElement)) { _rideRatingsState = RIDE_RATINGS_STATE_4; return; } + x = nextTrackElement.x; + y = nextTrackElement.y; + z = nextTrackElement.element->base_height * 8; + mapElement = nextTrackElement.element; if (x == RCT2_GLOBAL(0x0138B58A, uint16) && y == RCT2_GLOBAL(0x0138B58C, uint16) && z == RCT2_GLOBAL(0x0138B58E, uint16)) { _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; return; @@ -271,7 +263,7 @@ static void ride_ratings_update_state_2() RCT2_GLOBAL(0x0138B588, uint16) = z; RCT2_GLOBAL(0x0138B592, uint8) = mapElement->properties.track.type; } - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; } @@ -292,7 +284,7 @@ static void ride_ratings_update_state_3() ride_ratings_calculate(ride); RCT2_CALLPROC_X(0x00655F64, 0, 0, 0, 0, 0, (int)ride, 0); - ride_ratings_reliability_calculate(ride); + ride_ratings_calculate_value(ride); window_invalidate_by_number(WC_RIDE, _rideRatingsCurrentRide); _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; @@ -333,11 +325,11 @@ static void ride_ratings_update_state_5() y = RCT2_GLOBAL(0x0138B586, uint16) / 32; z = RCT2_GLOBAL(0x0138B588, uint16) / 8; - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + mapElement = map_get_first_element_at(x, y); trackType = RCT2_GLOBAL(0x0138B592, uint8); do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_TRACK) + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; if (mapElement->base_height != z) continue; @@ -347,7 +339,7 @@ static void ride_ratings_update_state_5() x = RCT2_GLOBAL(0x0138B584, uint16); y = RCT2_GLOBAL(0x0138B586, uint16); - if (!sub_6C6402(mapElement, &x, &y, &z)) { + if (!sub_6C6402(&mapElement, &x, &y, &z)) { _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; return; } @@ -363,7 +355,7 @@ static void ride_ratings_update_state_5() RCT2_GLOBAL(0x0138B588, uint16) = z; RCT2_GLOBAL(0x0138B592, uint8) = mapElement->properties.track.type; } - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; } @@ -373,15 +365,15 @@ static void ride_ratings_calculate(rct_ride *ride) ride_ratings_calculation calcFunc; calcFunc = ride_ratings_calculate_func_table[ride->type]; - if (calcFunc == NULL) { - calcFunc = RCT2_ADDRESS(0x0097E050, ride_ratings_calculation)[ride->type]; - RCT2_CALLPROC_X((int)calcFunc, 0, 0, 0, 0, 0, (int)ride, 0); - } else { + if (calcFunc != NULL) calcFunc(ride); - } + + // Original ride calculation + // calcFunc = RCT2_ADDRESS(0x0097E050, ride_ratings_calculation)[ride->type]; + // RCT2_CALLPROC_X((int)calcFunc, 0, 0, 0, 0, 0, (int)ride, 0); } -static void ride_ratings_reliability_calculate(rct_ride *ride) +static void ride_ratings_calculate_value(rct_ride *ride) { rct_ride *ride2; int i, otherRidesOfSameType; @@ -389,7 +381,7 @@ static void ride_ratings_reliability_calculate(rct_ride *ride) if (ride->excitement == (ride_rating)0xFFFF) return; - int reliability = + int value = (((ride->excitement * RCT2_GLOBAL(0x0097CD1E + (ride->type * 6), sint16)) * 32) >> 15) + (((ride->intensity * RCT2_GLOBAL(0x0097CD20 + (ride->type * 6), sint16)) * 32) >> 15) + (((ride->nausea * RCT2_GLOBAL(0x0097CD22 + (ride->type * 6), sint16)) * 32) >> 15); @@ -398,19 +390,19 @@ static void ride_ratings_reliability_calculate(rct_ride *ride) // New ride reward if (monthsOld <= 12) { - reliability += 10; + value += 10; if (monthsOld <= 4) - reliability += 20; + value += 20; } // Old ride penalty - if (monthsOld >= 40) reliability -= reliability / 4; - if (monthsOld >= 64) reliability -= reliability / 4; + if (monthsOld >= 40) value -= value / 4; + if (monthsOld >= 64) value -= value / 4; if (monthsOld < 200) { - if (monthsOld >= 88) reliability -= reliability / 4; - if (monthsOld >= 104) reliability -= reliability / 4; - if (monthsOld >= 120) reliability -= reliability / 2; - if (monthsOld >= 128) reliability -= reliability / 2; + if (monthsOld >= 88) value -= value / 4; + if (monthsOld >= 104) value -= value / 4; + if (monthsOld >= 120) value -= value / 2; + if (monthsOld >= 128) value -= value / 2; } // Other ride of same type penalty @@ -420,9 +412,9 @@ static void ride_ratings_reliability_calculate(rct_ride *ride) otherRidesOfSameType++; } if (otherRidesOfSameType > 1) - reliability -= reliability / 4; + value -= value / 4; - ride->reliability = max(0, reliability); + ride->value = max(0, value); } /** @@ -445,7 +437,7 @@ static uint16 ride_compute_upkeep(rct_ride *ride) dl = dl & 3; upkeep += trackCost * dl; - uint32 totalLength = (ride->length[0] + ride->length[1] + ride->length[2] + ride->length[3]) >> 16; + uint32 totalLength = ride_get_total_length(ride) >> 16; // The data originally here was 20's and 0's. The 20's all represented // rides that had tracks. The 0's were fixed rides like crooked house or @@ -502,11 +494,11 @@ static uint16 ride_compute_upkeep(rct_ride *ride) if (ride->mode == RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE) { upkeep += 30; - } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH) { + } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH_PASSTROUGH) { upkeep += 160; } else if (ride->mode == RIDE_MODE_LIM_POWERED_LAUNCH) { upkeep += 320; - } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH_35 || + } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED) { upkeep += 220; } @@ -543,11 +535,11 @@ static void ride_ratings_apply_adjustments(rct_ride *ride, rating_tuple *ratings uint16 flags = RCT2_GLOBAL(0x0097D4F2 + ride->type * 8, uint16); if (flags & 0x80) { uint16 totalAirTime = ride->total_air_time; - if (rideEntry->var_008 & 0x800) { - totalAirTime -= 96; - if (totalAirTime >= 0) { + if (rideEntry->flags & RIDE_ENTRY_FLAG_11) { + if (totalAirTime >= 96) { + totalAirTime -= 96; ratings->excitement -= totalAirTime / 8; - ratings->nausea -= totalAirTime / 16; + ratings->nausea += totalAirTime / 16; } } else { ratings->excitement += totalAirTime / 8; @@ -573,12 +565,16 @@ static void ride_ratings_apply_intensity_penalty(rating_tuple *ratings) } /** - * * rct2: 0x00655FD6 */ -static void sub_655FD6(rct_ride *ride) +static void set_unreliability_factor(rct_ride *ride) { - ride->var_198 += (ride->lift_hill_speed - RCT2_ADDRESS(0x0097D7C9, uint8)[ride->type * 4]) * 2; + // The higher the number, the lower the breakdown + // possibility. Range is [3, 7]. values are here: + // https://gist.github.com/kevinburke/123977c4884ccadbec70. Consider + // inlining this per ride + uint8 lift_speed_adjustment = RideLiftHillAdjustments[ride->type]; + ride->unreliability_factor += (ride->lift_hill_speed - lift_speed_adjustment) * 2; } /** @@ -593,28 +589,200 @@ static int sub_65E277() } /** - * + * Seems to calculate how much of the track is sheltered in eighths. * rct2: 0x0065E72D */ static int sub_65E72D(rct_ride *ride) { - int eax, ebx, ecx, edx, esi, edi, ebp; - edi = (int)ride; - RCT2_CALLFUNC_X(0x0065E277, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return edx & 0xFFFF; + int totalLength = ride_get_total_length(ride); + int shelteredLength = ride->sheltered_length; + int lengthEighth = totalLength / 8; + int lengthCounter = lengthEighth; + int numShelteredEighths = 0; + for (int i = 0; i < 7; i++) { + if (shelteredLength >= lengthCounter) { + lengthCounter += lengthEighth; + numShelteredEighths++; + } + } + + int dh = numShelteredEighths; + rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); + if (rideType->flags & RIDE_ENTRY_FLAG_COVERED_RIDE) + numShelteredEighths = 7; + + return (dh << 8) | numShelteredEighths; +} + +static rating_tuple get_var_10E_rating(rct_ride* ride) { + int var_10E_unk_1 = get_var_10E_unk_1(ride); + int var_10E_unk_2 = get_var_10E_unk_2(ride); + int var_10E_unk_3 = get_var_10E_unk_3(ride); + + int excitement = (var_10E_unk_1 * 0x28000) >> 16; + excitement += (var_10E_unk_2 * 0x30000) >> 16; + excitement += (var_10E_unk_3 * 63421) >> 16; + + int intensity = (var_10E_unk_1 * 81920) >> 16; + intensity += (var_10E_unk_2 * 49152) >> 16; + intensity += (var_10E_unk_3 * 21140) >> 16; + + int nausea = (var_10E_unk_1 * 0x50000) >> 16; + nausea += (var_10E_unk_2 * 0x32000) >> 16; + nausea += (var_10E_unk_3 * 42281) >> 16; + + rating_tuple rating = { excitement, intensity, nausea }; + return rating; } /** + * rct2: 0x0065DF72 + */ +static rating_tuple get_var_110_rating(rct_ride* ride) { + int var_110_unk_1 = get_var_110_unk_1(ride); + int var_110_unk_2 = get_var_110_unk_2(ride); + int var_110_unk_3 = get_var_110_unk_3(ride); + + int excitement = (var_110_unk_1 * 0x3C000) >> 16; + excitement += (var_110_unk_2 * 0x3C000) >> 16; + excitement += (var_110_unk_3 * 73992) >> 16; + + int intensity = (var_110_unk_1 * 0x14000) >> 16; + intensity += (var_110_unk_2 * 49152) >> 16; + intensity += (var_110_unk_3 * 21140) >> 16; + + int nausea = (var_110_unk_1 * 0x50000) >> 16; + nausea += (var_110_unk_2 * 0x32000) >> 16; + nausea += (var_110_unk_3 * 48623) >> 16; + + rating_tuple rating = { excitement, intensity, nausea }; + return rating; +} + +/** + * rct2: 0x0065E047 + */ +static rating_tuple get_var_112_rating(rct_ride *ride) { + int al; + + al = get_var_112_unk_1(ride); + al = min(al, 4); + int excitement = (al * 0x78000) >> 16; + + al = get_var_112_unk_1(ride); + al = min(al, 8); + int nausea = (al * 0x78000) >> 16; + + al = get_var_112_unk_2(ride); + al = min(al, 6); + excitement += (al * 273066) >> 16; + + al = get_var_112_unk_3(ride); + al = min(al, 6); + excitement += (al * 0x3AAAA) >> 16; + + al = get_var_112_unk_4(ride); + al = min(al, 7); + excitement += (al * 187245) >> 16; + + rating_tuple rating = { excitement, 0, nausea }; + return rating; +} + +/** + * rct2: 0x0065E0F2 + */ +static rating_tuple get_inversions_ratings(uint8 inversions) { + int excitement = (min(inversions, 6) * 0x1AAAAA) >> 16; + int intensity = (inversions * 0x320000) >> 16; + int nausea = (inversions * 0x15AAAA) >> 16; + + rating_tuple rating = { excitement, intensity, nausea }; + return rating; +} + +/* * + */ +static rating_tuple get_special_track_elements_rating(uint8 type, rct_ride *ride) { + int excitement = 0, intensity = 0, nausea = 0; + if (type == RIDE_TYPE_GHOST_TRAIN) { + if (ride_has_spinning_tunnel(ride)) { + excitement += 40; + intensity += 25; + nausea += 55; + } + } else if (type == RIDE_TYPE_LOG_FLUME) { + // Reverser for log flume + if (ride_has_log_reverser(ride)) { + excitement += 48; + intensity += 55; + nausea += 65; + } + } else { + if (ride_has_water_splash(ride)) { + excitement += 50; + intensity += 30; + nausea += 20; + } + if (ride_has_waterfall(ride)) { + excitement += 55; + intensity += 30; + } + if (ride_has_whirlpool(ride)) { + excitement += 35; + intensity += 20; + nausea += 23; + } + } + uint8 helix_sections = ride_get_helix_sections(ride); + int al = min(helix_sections, 9); + excitement += (al * 254862) >> 16; + + al = min(helix_sections, 11); + intensity += (al * 148945) >> 16; + + al = max(helix_sections - 5, 0); + al = min(al, 10); + nausea += (al * 0x140000) >> 16; + + rating_tuple rating = { excitement, intensity, nausea }; + return rating; +} + +/** * rct2: 0x0065DDD1 */ static rating_tuple sub_65DDD1(rct_ride *ride) { - int eax, ebx, ecx, edx, esi, edi, ebp; - edi = (int)ride; - RCT2_CALLFUNC_X(0x0065DDD1, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + int excitement = 0, intensity = 0, nausea = 0; - rating_tuple rating = { ebx, ecx, ebp }; + rating_tuple special_track_element_rating = get_special_track_elements_rating(ride->type, ride); + excitement += special_track_element_rating.excitement; + intensity += special_track_element_rating.intensity; + nausea += special_track_element_rating.nausea; + + rating_tuple var_10E_rating = get_var_10E_rating(ride); + excitement += var_10E_rating.excitement; + intensity += var_10E_rating.intensity; + nausea += var_10E_rating.nausea; + + rating_tuple var_110_rating = get_var_110_rating(ride); + excitement += var_110_rating.excitement; + intensity += var_110_rating.intensity; + nausea += var_110_rating.nausea; + + rating_tuple var_112_rating = get_var_112_rating(ride); + excitement += var_112_rating.excitement; + intensity += var_112_rating.intensity; + nausea += var_112_rating.nausea; + + rating_tuple inversions_rating = get_inversions_ratings(ride->inversions & 0x1F); + excitement += inversions_rating.excitement; + intensity += inversions_rating.intensity; + nausea += inversions_rating.nausea; + + rating_tuple rating = { excitement, intensity, nausea }; return rating; } @@ -624,11 +792,34 @@ static rating_tuple sub_65DDD1(rct_ride *ride) */ static rating_tuple sub_65E1C2(rct_ride *ride) { - int eax, ebx, ecx, edx, esi, edi, ebp; - edi = (int)ride; - RCT2_CALLFUNC_X(0x0065E1C2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + int sheltered_length_shifted = (ride->sheltered_length) >> 16; + uint32 eax = min(sheltered_length_shifted, 1000); + int excitement = (eax * 9175) >> 16; - rating_tuple rating = { ebx, ecx, ebp }; + eax = min(sheltered_length_shifted, 2000); + int intensity = (eax * 0x2666) >> 16; + + eax = min(sheltered_length_shifted, 1000); + int nausea = (eax * 0x4000) >> 16; + + /*eax = (ride->var_11C * 30340) >> 16;*/ + /*nausea += eax;*/ + + if (ride->num_sheltered_sections & 0x40) { + excitement += 20; + nausea += 15; + } + + if (ride->num_sheltered_sections & 0x20) { + excitement += 20; + nausea += 15; + } + + uint8 lowerval = ride->num_sheltered_sections & 0x1F; + lowerval = min(lowerval, 11); + excitement += (lowerval * 774516) >> 16; + + rating_tuple rating = { excitement, intensity, nausea }; return rating; } @@ -658,7 +849,7 @@ static rating_tuple ride_ratings_get_gforce_ratings(rct_ride *ride) // Apply lateral G force factor result.excitement += (min(FIXED_2DP(1,50), ride->max_lateral_g) * 26214) >> 16; - result.intensity += (ride->max_lateral_g * 65536) >> 16; + result.intensity += ride->max_lateral_g; result.nausea += (ride->max_lateral_g * 21845) >> 16; // Very high lateral G force penalty @@ -725,7 +916,7 @@ static int ride_ratings_get_scenery_score(rct_ride *ride) x = stationXY & 0xFF; y = stationXY >> 8; - z = map_element_height(x * 32, y * 32); + z = map_element_height(x * 32, y * 32) & 0xFFFF; // Check if station is underground, returns a fixed mediocre score since you can't have scenery underground if (z > ride->station_heights[i] * 8) @@ -733,130 +924,208 @@ static int ride_ratings_get_scenery_score(rct_ride *ride) // Count surrounding scenery items numSceneryItems = 0; - for (yy = y - 5; yy <= y + 5; yy++) { - for (xx = x - 5; xx <= x + 5; xx++) { + for (yy = max(y - 5, 0); yy <= min(y + 5, 255); yy++) { + for (xx = max(x - 5, 0); xx <= min(x + 5, 255); xx++) { // Count scenery items on this tile - mapElement = TILE_MAP_ELEMENT_POINTER(yy * 256 + xx); + mapElement = map_get_first_element_at(xx, yy); do { - if (mapElement->flags & 0x10) + if (mapElement->flags & (1 << 4)) continue; - type = mapElement->type & MAP_ELEMENT_TYPE_MASK; + type = map_element_get_type(mapElement); if (type == MAP_ELEMENT_TYPE_SCENERY || type == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) numSceneryItems++; - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); } } return min(numSceneryItems, 47) * 5; } +#pragma region Ride rating calculation helpers + +static void ride_ratings_set(rating_tuple *ratings, int excitement, int intensity, int nausea) +{ + ratings->excitement = excitement; + ratings->intensity = intensity; + ratings->nausea = nausea; +} + +static void ride_ratings_apply_length(rating_tuple *ratings, rct_ride *ride, int maxLength, int excitementMultiplier) +{ + ratings->excitement += (min(ride_get_total_length(ride) >> 16, maxLength) * excitementMultiplier) >> 16; +} + +static void ride_ratings_apply_synchronisation(rating_tuple *ratings, rct_ride *ride, int excitement, int intensity) +{ + if (ride->depart_flags & RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS) { + ratings->excitement += excitement; + ratings->intensity += intensity; + } +} + +static void ride_ratings_apply_train_length(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier) +{ + ratings->excitement += ((ride->num_cars_per_train - 1) * excitementMultiplier) >> 16; +} + +static void ride_ratings_apply_max_speed(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier, int intensityMultiplier, int nauseaMultiplier) +{ + ratings->excitement += ((ride->max_speed >> 16) * excitementMultiplier) >> 16; + ratings->intensity += ((ride->max_speed >> 16) * intensityMultiplier) >> 16; + ratings->nausea += ((ride->max_speed >> 16) * nauseaMultiplier) >> 16; +} + +static void ride_ratings_apply_average_speed(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier, int intensityMultiplier) +{ + ratings->excitement += ((ride->average_speed >> 16) * excitementMultiplier) >> 16; + ratings->intensity += ((ride->average_speed >> 16) * intensityMultiplier) >> 16; +} + +static void ride_ratings_apply_duration(rating_tuple *ratings, rct_ride *ride, int maxDuration, int excitementMultiplier) +{ + ratings->excitement += (min(ride_get_total_time(ride), maxDuration) * excitementMultiplier) >> 16; +} + +static void ride_ratings_apply_gforces(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier, int intensityMultiplier, int nauseaMultiplier) +{ + rating_tuple subRating = ride_ratings_get_gforce_ratings(ride); + ratings->excitement += (subRating.excitement * excitementMultiplier) >> 16; + ratings->intensity += (subRating.intensity * intensityMultiplier) >> 16; + ratings->nausea += (subRating.nausea * nauseaMultiplier) >> 16; +} + +static void ride_ratings_apply_65DDD1(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier, int intensityMultiplier, int nauseaMultiplier) +{ + rating_tuple subRating = sub_65DDD1(ride); + ratings->excitement += (subRating.excitement * excitementMultiplier) >> 16; + ratings->intensity += (subRating.intensity * intensityMultiplier) >> 16; + ratings->nausea += (subRating.nausea * nauseaMultiplier) >> 16; +} + +static void ride_ratings_apply_drops(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier, int intensityMultiplier, int nauseaMultiplier) +{ + rating_tuple subRating = ride_ratings_get_drop_ratings(ride); + ratings->excitement += (subRating.excitement * excitementMultiplier) >> 16; + ratings->intensity += (subRating.intensity * intensityMultiplier) >> 16; + ratings->nausea += (subRating.nausea * nauseaMultiplier) >> 16; +} + +static void ride_ratings_apply_65E1C2(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier, int intensityMultiplier, int nauseaMultiplier) +{ + rating_tuple subRating = sub_65E1C2(ride); + ratings->excitement += (subRating.excitement * excitementMultiplier) >> 16; + ratings->intensity += (subRating.intensity * intensityMultiplier) >> 16; + ratings->nausea += (subRating.nausea * nauseaMultiplier) >> 16; +} + +static void ride_ratings_apply_operation_option(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier, int intensityMultiplier, int nauseaMultiplier) +{ + ratings->excitement += (ride->operation_option * excitementMultiplier) >> 16; + ratings->intensity += (ride->operation_option * intensityMultiplier) >> 16; + ratings->nausea += (ride->operation_option * nauseaMultiplier) >> 16; +} + +static void ride_ratings_apply_65E277(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier) +{ + ratings->excitement += (sub_65E277() * excitementMultiplier) >> 16; +} + +static void ride_ratings_apply_scenery(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier) +{ + ratings->excitement += (ride_ratings_get_scenery_score(ride) * excitementMultiplier) >> 16; +} + +static void ride_ratings_apply_highest_drop_height_penalty(rating_tuple *ratings, rct_ride *ride, int minHighestDropHeight, int excitementPenalty, int intensityPenalty, int nauseaPenalty) +{ + if (ride->highest_drop_height < minHighestDropHeight) { + ratings->excitement /= excitementPenalty; + ratings->intensity /= intensityPenalty; + ratings->nausea /= nauseaPenalty; + } +} + +static void ride_ratings_apply_max_speed_penalty(rating_tuple *ratings, rct_ride *ride, int minMaxSpeed, int excitementPenalty, int intensityPenalty, int nauseaPenalty) +{ + if (ride->max_speed < minMaxSpeed) { + ratings->excitement /= excitementPenalty; + ratings->intensity /= intensityPenalty; + ratings->nausea /= nauseaPenalty; + } +} + +static void ride_ratings_apply_num_drops_penalty(rating_tuple *ratings, rct_ride *ride, int minNumDrops, int excitementPenalty, int intensityPenalty, int nauseaPenalty) +{ + if ((ride->drops & 0x3F) < minNumDrops) { + ratings->excitement /= excitementPenalty; + ratings->intensity /= intensityPenalty; + ratings->nausea /= nauseaPenalty; + } +} + +static void ride_ratings_apply_max_negative_g_penalty(rating_tuple *ratings, rct_ride *ride, int maxMaxNegativeVerticalG, int excitementPenalty, int intensityPenalty, int nauseaPenalty) +{ + if (ride->max_negative_vertical_g >= maxMaxNegativeVerticalG) { + ratings->excitement /= excitementPenalty; + ratings->intensity /= intensityPenalty; + ratings->nausea /= nauseaPenalty; + } +} + +static void ride_ratings_apply_max_lateral_g_penalty(rating_tuple *ratings, rct_ride *ride, int minMaxLateralG, int excitementPenalty, int intensityPenalty, int nauseaPenalty) +{ + if (ride->max_lateral_g < minMaxLateralG) { + ratings->excitement /= excitementPenalty; + ratings->intensity /= intensityPenalty; + ratings->nausea /= nauseaPenalty; + } +} + +static void ride_ratings_apply_first_length_penalty(rating_tuple *ratings, rct_ride *ride, int minFirstLength, int excitementPenalty, int intensityPenalty, int nauseaPenalty) +{ + if (ride->length[0] < minFirstLength) { + ratings->excitement /= excitementPenalty; + ratings->intensity /= intensityPenalty; + ratings->nausea /= nauseaPenalty; + } +} + +#pragma endregion + #pragma region Ride rating calculation functions -static void ride_ratings_calculate_mine_train_coaster(rct_ride *ride) +static void ride_ratings_calculate_spiral_roller_coaster(rct_ride *ride) { - rating_tuple ratings, subRating; - int totalLength, time; + rating_tuple ratings; if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - ride->var_198 = 16; - sub_655FD6(ride); + ride->unreliability_factor = 14; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(2,90); - ratings.intensity = RIDE_RATING(2,30); - ratings.nausea = RIDE_RATING(2,10); - - // Apply length of ride factor - totalLength = (ride->length[0] + ride->length[1] + ride->length[2] + ride->length[3]) >> 16; - ratings.excitement += (min(6000, totalLength) * 764) >> 16; - - // Apply racing coaster factor - if (ride->depart_flags & RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS) { - ratings.excitement += RIDE_RATING(0,40); - ratings.intensity += RIDE_RATING(0,05); - } - - // Apply length of train factor - ratings.excitement += ((ride->num_cars_per_train - 1) * 187245) >> 16; - - // Apply maximum speed factor - ratings.excitement += ((ride->max_speed >> 16) * 44281) >> 16; - ratings.intensity += ((ride->max_speed >> 16) * 88562) >> 16; - ratings.nausea += ((ride->max_speed >> 16) * 35424) >> 16; - - // Apply average speed factor - ratings.excitement += ((ride->average_speed >> 16) * 291271) >> 16; - ratings.intensity += ((ride->average_speed >> 16) * 436906) >> 16; + ride_ratings_set(&ratings, RIDE_RATING(3,30), RIDE_RATING(0,30), RIDE_RATING(0,30)); + ride_ratings_apply_length(&ratings, ride, 6000, 819); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 140434); + ride_ratings_apply_max_speed(&ratings, ride, 51366, 85019, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 400497); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 36864, 30384, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 28235, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 43690, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); - // Apply ride duration factor - time = ride->time[0] + ride->time[1] + ride->time[2] + ride->time[3]; - ratings.excitement += (min(150, time) * 26214) >> 16; - - // Apply G forces factor - subRating = ride_ratings_get_gforce_ratings(ride); - ratings.excitement += (subRating.excitement * 40960) >> 16; - ratings.intensity += (subRating.intensity * 35746) >> 16; - ratings.nausea += (subRating.nausea * 49648) >> 16; - - // Apply ? - subRating = sub_65DDD1(ride); - ratings.excitement += (subRating.excitement * 29721) >> 16; - ratings.intensity += (subRating.intensity * 34767) >> 16; - ratings.nausea += (subRating.nausea * 45749) >> 16; - - // Apply drops factor - subRating = ride_ratings_get_drop_ratings(ride); - ratings.excitement += (subRating.excitement * 29127) >> 16; - ratings.intensity += (subRating.intensity * 46811) >> 16; - ratings.nausea += (subRating.nausea * 49152) >> 16; - - // Apply ? - subRating = sub_65E1C2(ride); - ratings.excitement += (subRating.excitement * 19275) >> 16; - ratings.intensity += (subRating.intensity * 32768) >> 16; - ratings.nausea += (subRating.nausea * 35108) >> 16; - - // Apply ? - ratings.excitement += (sub_65E277() * 21472) >> 16; - - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 16732) >> 16; - - // Apply low highest drop penalty - if (ride->highest_drop_height < 8) { - ride->excitement /= 2; - ride->intensity /= 2; - ride->nausea /= 2; - } - - // Apply low max speed penalty - if (ride->max_speed < 0xA0000) { - ride->excitement /= 2; - ride->intensity /= 2; - ride->nausea /= 2; - } - - // Apply low maximum negative vertical G force penalty - if (ride->max_negative_vertical_g > FIXED_2DP(0,10)) { - ride->excitement /= 2; - ride->intensity /= 2; - ride->nausea /= 2; - } - - // Apply short ride penalty - if (ride->length[0] < 0x1720000) { - ride->excitement /= 2; - ride->intensity /= 2; - ride->nausea /= 2; - } - - // Apply low number of drops penalty - if ((ride->drops & 0x3F) < 2) { - ride->excitement /= 2; - ride->intensity /= 2; - ride->nausea /= 2; + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) { + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0, 40), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); } ride_ratings_apply_intensity_penalty(&ratings); @@ -865,7 +1134,756 @@ static void ride_ratings_calculate_mine_train_coaster(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_stand_up_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 17; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,50), RIDE_RATING(3,00), RIDE_RATING(3,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,10)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 123987, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 35746, 59578); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 34952, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 12850, 28398, 30427); + ride_ratings_apply_65E277(&ratings, ride, 17893); + ride_ratings_apply_scenery(&ratings, ride, 5577); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,50), 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_suspended_swinging_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 18; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,30), RIDE_RATING(2,90), RIDE_RATING(3,50)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,10)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 32768, 23831, 79437); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 48036); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6971); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 8, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xC0000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0, 60), 2, 2, 2); + ride_ratings_apply_max_lateral_g_penalty(&ratings, ride, FIXED_2DP(1, 50), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x1720000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_inverted_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 17; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,60), RIDE_RATING(2,80), RIDE_RATING(3,20)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,42), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 29789, 55606); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 29552, 57186); + ride_ratings_apply_drops(&ratings, ride, 29127, 39009, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 15291, 35108); + ride_ratings_apply_65E277(&ratings, ride, 15657); + ride_ratings_apply_scenery(&ratings, ride, 8366); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,30), 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_junior_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 13; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,40), RIDE_RATING(2,50), RIDE_RATING(1,80)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 20480, 23831, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 25700, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 9760); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 6, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x70000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 1, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_miniature_railway(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 11; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,50), RIDE_RATING(0,00), RIDE_RATING(0,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_train_length(&ratings, ride, 140434); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_65E1C2(&ratings, ride, 4294960871, 6553, 23405); + ride_ratings_apply_65E277(&ratings, ride, 8946); + ride_ratings_apply_scenery(&ratings, ride, 20915); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xC80000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + int edx = sub_65E72D(ride); + if (((edx >> 8) & 0xFF) >= 4) + ride->excitement /= 4; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_monorail(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,00), RIDE_RATING(0,00), RIDE_RATING(0,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_train_length(&ratings, ride, 93622); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 70849, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 218453); + ride_ratings_apply_duration(&ratings, ride, 150, 21845); + ride_ratings_apply_65E1C2(&ratings, ride, 5140, 6553, 18724); + ride_ratings_apply_65E277(&ratings, ride, 8946); + ride_ratings_apply_scenery(&ratings, ride, 16732); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xAA0000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + int edx = sub_65E72D(ride); + if (((edx >> 8) & 0xFF) >= 4) + ride->excitement /= 4; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_mini_suspended_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 15; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,80), RIDE_RATING(2,50), RIDE_RATING(2,70)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,45), RIDE_RATING(0,15)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 34179, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 58254, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 19275, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 13943); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 6, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x80000, 2, 2, 2); + ride_ratings_apply_max_lateral_g_penalty(&ratings, ride, FIXED_2DP(1,30), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xC80000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_boat_ride(rct_ride *ride) +{ + rating_tuple ratings; + + ride->unreliability_factor = 7; + set_unreliability_factor(ride); + + // NOTE In the original game, the ratings were zeroed before calling set_unreliability_factor which is unusual as rest of + // the calculation functions do this before hand. This is because set_unreliability_factor alters the value of + // ebx (excitement). This is assumed to be a bug and therefore fixed. + + ride_ratings_set(&ratings, RIDE_RATING(1,90), RIDE_RATING(0,80), RIDE_RATING(0,90)); + + // Most likely checking if the ride has does not have a circuit + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + ratings.excitement += RIDE_RATING(0,20); + + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 22310); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= 0 << 5; +} + +static void ride_ratings_calculate_wooden_wild_mouse(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,90), RIDE_RATING(2,90), RIDE_RATING(2,10)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0, 8)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 655360); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 102400, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 29721, 43458, 45749); + ride_ratings_apply_drops(&ratings, ride, 40777, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 17893); + ride_ratings_apply_scenery(&ratings, ride, 5577); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 6, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x70000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,10), 2, 2, 2); + ride_ratings_apply_max_lateral_g_penalty(&ratings, ride, FIXED_2DP(1,50), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xAA0000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 3, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_steeplechase(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,70), RIDE_RATING(2,40), RIDE_RATING(1,80)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,75), RIDE_RATING(0, 9)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 20480, 20852, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 25700, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 9760); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 4, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x80000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,50), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xF00000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_car_ride(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 12; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,00), RIDE_RATING(0,50), RIDE_RATING(0,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,15), RIDE_RATING(0,00)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_65DDD1(&ratings, ride, 14860, 0, 11437); + ride_ratings_apply_drops(&ratings, ride, 8738, 0, 0); + ride_ratings_apply_65E1C2(&ratings, ride, 12850, 6553, 4681); + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 8366); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xC80000, 8, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_launched_freefall(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,70), RIDE_RATING(3,00), RIDE_RATING(3,50)); + + if (ride->mode == RIDE_MODE_DOWNWARD_LAUNCH) { + ratings.excitement += RIDE_RATING(0,30); + ratings.intensity += RIDE_RATING(0,65); + ratings.nausea += RIDE_RATING(0,45); + } + + ratings.excitement += ((ride_get_total_length(ride) >> 16) * 32768) >> 16; + ride_ratings_apply_operation_option(&ratings, ride, 0, 1355917, 451972); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 25098); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_bobsleigh_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,80), RIDE_RATING(3,20), RIDE_RATING(2,50)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,20), RIDE_RATING(0,00)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 65536, 23831, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 5577); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xC0000, 2, 2, 2); + ride_ratings_apply_max_lateral_g_penalty(&ratings, ride, FIXED_2DP(1,20), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x1720000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_observation_tower(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 15; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,50), RIDE_RATING(0,00), RIDE_RATING(0,10)); + ratings.excitement += ((ride_get_total_length(ride) >> 16) * 45875) >> 16; + ratings.nausea += ((ride_get_total_length(ride) >> 16) * 26214) >> 16; + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 83662); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= 7 << 5; + + int edx = sub_65E72D(ride); + if (((edx >> 8) & 0xFF) >= 5) + ride->excitement /= 4; +} + +static void ride_ratings_calculate_looping_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = ride_is_powered_launched(ride) ? 20 : 15; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,00), RIDE_RATING(0,50), RIDE_RATING(0,20)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 14, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) { + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0, 10), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + } + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_dinghy_slide(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 13; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,70), RIDE_RATING(2,00), RIDE_RATING(1,50)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,50), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 65536, 29789, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 5577); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x70000, 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x8C0000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_mine_train_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,90), RIDE_RATING(2,30), RIDE_RATING(2,10)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 40960, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 29721, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 19275, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 21472); + ride_ratings_apply_scenery(&ratings, ride, 16732); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 8, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,10), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x1720000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_chairlift(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14 + (ride->speed * 2); + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,60), RIDE_RATING(0,40), RIDE_RATING(0,50)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_65DDD1(&ratings, ride, 7430, 3476, 4574); + ride_ratings_apply_65E1C2(&ratings, ride, 4294948021, 21845, 23405); + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 25098); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x960000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + if (ride->num_stations <= 1) { + ratings.excitement = 0; + ratings.intensity /= 2; + } + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + int edx = sub_65E72D(ride); + if (((edx >> 8) & 0xFF) >= 4) + ride->excitement /= 4; + + ride->inversions &= 0x1F; + ride->inversions |= edx << 5; +} + +static void ride_ratings_calculate_corkscrew_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,00), RIDE_RATING(0,50), RIDE_RATING(0,20)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) { + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0, 40), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + } + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= sub_65E72D(ride) << 5; @@ -877,20 +1895,16 @@ static void ride_ratings_calculate_maze(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 8; - sub_655FD6(ride); + ride->unreliability_factor = 8; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(1,30); - ratings.intensity = RIDE_RATING(0,50); - ratings.nausea = RIDE_RATING(0,00); + ride_ratings_set(&ratings, RIDE_RATING(1,30), RIDE_RATING(0,50), RIDE_RATING(0,00)); - // Apply size factor - int unk = min(ride->maze_tiles, 100); - ratings.excitement += unk; - ratings.intensity += unk / 2; + int size = min(ride->maze_tiles, 100); + ratings.excitement += size; + ratings.intensity += size * 2; - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 22310) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 22310); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -898,7 +1912,7 @@ static void ride_ratings_calculate_maze(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; @@ -910,13 +1924,10 @@ static void ride_ratings_calculate_spiral_slide(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 8; - sub_655FD6(ride); + ride->unreliability_factor = 8; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(1,50); - ratings.intensity = RIDE_RATING(1,40); - ratings.nausea = RIDE_RATING(0,90); + ride_ratings_set(&ratings, RIDE_RATING(1,50), RIDE_RATING(1,40), RIDE_RATING(0,90)); // Unlimited slides boost if (ride->mode == RIDE_MODE_UNLIMITED_RIDES_PER_ADMISSION) { @@ -925,7 +1936,7 @@ static void ride_ratings_calculate_spiral_slide(rct_ride *ride) ratings.nausea += RIDE_RATING(0, 25); } - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 25098) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 25098); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -933,31 +1944,176 @@ static void ride_ratings_calculate_spiral_slide(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 2 << 5; } +static void ride_ratings_calculate_go_karts(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,42), RIDE_RATING(1,73), RIDE_RATING(0,40)); + ride_ratings_apply_length(&ratings, ride, 700, 32768); + + if (ride->mode == RIDE_MODE_RACE && ride->num_vehicles >= 4) { + ratings.excitement += RIDE_RATING(1,40); + ratings.intensity += RIDE_RATING(0,50); + + int lapsFactor = (ride->num_laps - 1) * 30; + ratings.excitement += lapsFactor; + ratings.intensity += lapsFactor / 2; + } + + ride_ratings_apply_65DDD1(&ratings, ride, 4458, 3476, 5718); + ride_ratings_apply_drops(&ratings, ride, 8738, 5461, 6553); + ride_ratings_apply_65E1C2(&ratings, ride, 2570, 8738, 2340); + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 16732); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + int edx = sub_65E72D(ride); + + ride->inversions &= 0x1F; + ride->inversions |= edx << 5; + + if (((edx >> 8) & 0xFF) >= 6) + ride->excitement /= 2; +} + +static void ride_ratings_calculate_log_flume(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 15; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,50), RIDE_RATING(0,55), RIDE_RATING(0,30)); + ride_ratings_apply_length(&ratings, ride, 2000, 7208); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_max_speed(&ratings, ride, 531372, 655360, 301111); + ride_ratings_apply_duration(&ratings, ride, 300, 13107); + ride_ratings_apply_65DDD1(&ratings, ride, 22291, 20860, 4574); + ride_ratings_apply_drops(&ratings, ride, 69905, 62415, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 22367); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_river_rapids(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,20), RIDE_RATING(0,70), RIDE_RATING(0,50)); + ride_ratings_apply_length(&ratings, ride, 2000, 6225); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,30), RIDE_RATING(0,05)); + ride_ratings_apply_max_speed(&ratings, ride, 115130, 159411, 106274); + ride_ratings_apply_duration(&ratings, ride, 500, 13107); + ride_ratings_apply_65DDD1(&ratings, ride, 29721, 22598, 5718); + ride_ratings_apply_drops(&ratings, ride, 40777, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 31314); + ride_ratings_apply_scenery(&ratings, ride, 13943); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 2, 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xC80000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_dodgems(rct_ride *ride) +{ + rating_tuple ratings; + + ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; + ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,30), RIDE_RATING(0,50), RIDE_RATING(0,35)); + + if (ride->num_vehicles >= 4) + ratings.excitement += RIDE_RATING(0,40); + + ratings.excitement += ride->operation_option; + ratings.intensity += ride->operation_option / 2; + + if (ride->num_vehicles >= 4) + ratings.excitement += RIDE_RATING(0,40); + + ride_ratings_apply_scenery(&ratings, ride, 5577); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= 7 << 5; +} + static void ride_ratings_calculate_pirate_ship(rct_ride *ride) { rating_tuple ratings; ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 10; - sub_655FD6(ride); + ride->unreliability_factor = 10; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(1,50); - ratings.intensity = RIDE_RATING(1,90); - ratings.nausea = RIDE_RATING(1,41); + ride_ratings_set(&ratings, RIDE_RATING(1,50), RIDE_RATING(1,90), RIDE_RATING(1,41)); - ratings.excitement += ride->var_0D0 * 5; - ratings.intensity += ride->var_0D0 * 5; - ratings.nausea += ride->var_0D0 * 10; + ratings.excitement += ride->operation_option * 5; + ratings.intensity += ride->operation_option * 5; + ratings.nausea += ride->operation_option * 10; - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 16732) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 16732); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -965,7 +2121,7 @@ static void ride_ratings_calculate_pirate_ship(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; @@ -977,19 +2133,16 @@ static void ride_ratings_calculate_inverter_ship(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 16; - sub_655FD6(ride); + ride->unreliability_factor = 16; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(2,50); - ratings.intensity = RIDE_RATING(2,70); - ratings.nausea = RIDE_RATING(2,74); + ride_ratings_set(&ratings, RIDE_RATING(2,50), RIDE_RATING(2,70), RIDE_RATING(2,74)); - ratings.excitement += ride->var_0D0 * 11; - ratings.intensity += ride->var_0D0 * 22; - ratings.nausea += ride->var_0D0 * 22; + ratings.excitement += ride->operation_option * 11; + ratings.intensity += ride->operation_option * 22; + ratings.nausea += ride->operation_option * 22; - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 11155) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -997,7 +2150,7 @@ static void ride_ratings_calculate_inverter_ship(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; @@ -1006,19 +2159,19 @@ static void ride_ratings_calculate_inverter_ship(rct_ride *ride) static void ride_ratings_calculate_food_stall(rct_ride *ride) { ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; } static void ride_ratings_calculate_drink_stall(rct_ride *ride) { ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; } static void ride_ratings_calculate_shop(rct_ride *ride) { ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; } static void ride_ratings_calculate_merry_go_round(rct_ride *ride) @@ -1027,13 +2180,17 @@ static void ride_ratings_calculate_merry_go_round(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 16; - sub_655FD6(ride); + ride->unreliability_factor = 16; + set_unreliability_factor(ride); - int unk = ride->var_0D0 * 5; - ratings.excitement = unk + RIDE_RATING(0,60) + ((ride_ratings_get_scenery_score(ride) * 19521) >> 16); - ratings.intensity = unk + RIDE_RATING(0,15); - ratings.nausea = unk + RIDE_RATING(0,30); + ride_ratings_set(&ratings, RIDE_RATING(0,60), RIDE_RATING(0,15), RIDE_RATING(0,30)); + + int rotationsFactor = ride->rotations * 5; + ratings.excitement += rotationsFactor; + ratings.intensity += rotationsFactor; + ratings.nausea += rotationsFactor; + + ride_ratings_apply_scenery(&ratings, ride, 19521); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1041,7 +2198,7 @@ static void ride_ratings_calculate_merry_go_round(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 7 << 5; @@ -1050,13 +2207,13 @@ static void ride_ratings_calculate_merry_go_round(rct_ride *ride) static void ride_ratings_calculate_information_kiosk(rct_ride *ride) { ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; } -static void ride_ratings_calculate_bathroom(rct_ride *ride) +static void ride_ratings_calculate_toilets(rct_ride *ride) { ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; } static void ride_ratings_calculate_ferris_wheel(rct_ride *ride) @@ -1065,13 +2222,17 @@ static void ride_ratings_calculate_ferris_wheel(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 16; - sub_655FD6(ride); + ride->unreliability_factor = 16; + set_unreliability_factor(ride); - int unk = ride->var_0D0 * 25; - ratings.excitement = unk + RIDE_RATING(0,60) + ((ride_ratings_get_scenery_score(ride) * 41831) >> 16); - ratings.intensity = unk + RIDE_RATING(0,25); - ratings.nausea = unk + RIDE_RATING(0,30); + ride_ratings_set(&ratings, RIDE_RATING(0,60), RIDE_RATING(0,25), RIDE_RATING(0,30)); + + int rotationsFactor = ride->rotations * 25; + ratings.excitement += rotationsFactor; + ratings.intensity += rotationsFactor; + ratings.nausea += rotationsFactor; + + ride_ratings_apply_scenery(&ratings, ride, 41831); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1079,7 +2240,7 @@ static void ride_ratings_calculate_ferris_wheel(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; @@ -1091,18 +2252,18 @@ static void ride_ratings_calculate_motion_simulator(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 21; - sub_655FD6(ride); + ride->unreliability_factor = 21; + set_unreliability_factor(ride); // Base ratings if (ride->mode == RIDE_MODE_FILM_THRILL_RIDERS) { - ratings.excitement = RIDE_RATING(2,90); - ratings.intensity = RIDE_RATING(3,50); - ratings.nausea = RIDE_RATING(3,00); - } else { ratings.excitement = RIDE_RATING(3,25); ratings.intensity = RIDE_RATING(4,10); ratings.nausea = RIDE_RATING(3,30); + } else { + ratings.excitement = RIDE_RATING(2,90); + ratings.intensity = RIDE_RATING(3,50); + ratings.nausea = RIDE_RATING(3,00); } ride_ratings_apply_intensity_penalty(&ratings); @@ -1111,7 +2272,7 @@ static void ride_ratings_calculate_motion_simulator(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 7 << 5; @@ -1123,8 +2284,8 @@ static void ride_ratings_calculate_3d_cinema(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 21; - sub_655FD6(ride); + ride->unreliability_factor = 21; + set_unreliability_factor(ride); // Base ratings switch (ride->mode) { @@ -1152,7 +2313,7 @@ static void ride_ratings_calculate_3d_cinema(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 7 << 5; @@ -1164,8 +2325,8 @@ static void ride_ratings_calculate_top_spin(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 19; - sub_655FD6(ride); + ride->unreliability_factor = 19; + set_unreliability_factor(ride); // Base ratings switch (ride->mode) { @@ -1187,7 +2348,7 @@ static void ride_ratings_calculate_top_spin(rct_ride *ride) break; } - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 11155) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1195,7 +2356,7 @@ static void ride_ratings_calculate_top_spin(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; @@ -1207,15 +2368,11 @@ static void ride_ratings_calculate_space_rings(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 7; - sub_655FD6(ride); + ride->unreliability_factor = 7; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(1,50); - ratings.intensity = RIDE_RATING(2,10); - ratings.nausea = RIDE_RATING(6,50); - - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 25098) >> 16; + ride_ratings_set(&ratings, RIDE_RATING(1,50), RIDE_RATING(2,10), RIDE_RATING(6,50)); + ride_ratings_apply_scenery(&ratings, ride, 25098); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1223,13 +2380,45 @@ static void ride_ratings_calculate_space_rings(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; } -static void ride_ratings_calculate_elevator(rct_ride *ride) +static void ride_ratings_calculate_reverse_freefall_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 25; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,00), RIDE_RATING(3,20), RIDE_RATING(2,80)); + ride_ratings_apply_length(&ratings, ride, 6000, 327); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,60), RIDE_RATING(0,15)); + ride_ratings_apply_max_speed(&ratings, ride, 436906, 436906, 320398); + ride_ratings_apply_gforces(&ratings, ride, 24576, 41704, 59578); + ride_ratings_apply_65E1C2(&ratings, ride, 12850, 28398, 11702); + ride_ratings_apply_65E277(&ratings, ride, 17893); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 34, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_lift(rct_ride *ride) { rating_tuple ratings; int totalLength; @@ -1237,20 +2426,17 @@ static void ride_ratings_calculate_elevator(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - ride->var_198 = 15; - sub_655FD6(ride); + ride->unreliability_factor = 15; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(1,11); - ratings.intensity = RIDE_RATING(0,35); - ratings.nausea = RIDE_RATING(0,30); + ride_ratings_set(&ratings, RIDE_RATING(1,11), RIDE_RATING(0,35), RIDE_RATING(0,30)); - // Apply length factor - totalLength = ride->length[0] + ride->length[1] + ride->length[2] + ride->length[3]; - ratings.excitement += ((totalLength >> 16) * 45875) >> 16; - ratings.excitement += (sub_65E277() * 11183) >> 16; - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 83662) >> 16; - ratings.nausea += ((totalLength >> 16) * 26214) >> 16; + totalLength = ride_get_total_length(ride) >> 16; + ratings.excitement += (totalLength * 45875) >> 16; + ratings.nausea += (totalLength * 26214) >> 16; + + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 83662); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1258,7 +2444,7 @@ static void ride_ratings_calculate_elevator(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 7 << 5; @@ -1267,10 +2453,49 @@ static void ride_ratings_calculate_elevator(rct_ride *ride) ride->excitement /= 4; } -static void ride_ratings_calculate_atm(rct_ride *ride) +static void ride_ratings_calculate_vertical_drop_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,20), RIDE_RATING(0,80), RIDE_RATING(0,30)); + ride_ratings_apply_length(&ratings, ride, 4000, 1146); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_max_speed(&ratings, ride, 97418, 141699, 70849); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 40960, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 58254, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 20, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,10), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 1, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_cash_machine(rct_ride *ride) { ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; } static void ride_ratings_calculate_twist(rct_ride *ride) @@ -1279,19 +2504,16 @@ static void ride_ratings_calculate_twist(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 16; - sub_655FD6(ride); + ride->unreliability_factor = 16; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(1,13); - ratings.intensity = RIDE_RATING(0,97); - ratings.nausea = RIDE_RATING(1,90); + ride_ratings_set(&ratings, RIDE_RATING(1,13), RIDE_RATING(0,97), RIDE_RATING(1,90)); - ratings.excitement += ride->var_0D0 * 20; - ratings.intensity += ride->var_0D0 * 20; - ratings.nausea += ride->var_0D0 * 20; + ratings.excitement += ride->rotations * 20; + ratings.intensity += ride->rotations * 20; + ratings.nausea += ride->rotations * 20; - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 13943) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 13943); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1299,7 +2521,7 @@ static void ride_ratings_calculate_twist(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; @@ -1311,8 +2533,8 @@ static void ride_ratings_calculate_haunted_house(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 8; - sub_655FD6(ride); + ride->unreliability_factor = 8; + set_unreliability_factor(ride); ratings.excitement = RIDE_RATING(3,41); ratings.intensity = RIDE_RATING(1,53); @@ -1324,47 +2546,357 @@ static void ride_ratings_calculate_haunted_house(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0xE0; } -static void ride_ratings_calculate_mini_golf(rct_ride *ride) +static void ride_ratings_calculate_flying_roller_coaster(rct_ride *ride) { - rating_tuple ratings, unkRating; + rating_tuple ratings; - // RCT2_CALLPROC_X(0x0065BF97, 0, 0, 0, 0, 0, (int)ride, 0); return; + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 17; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(4,35), RIDE_RATING(1,85), RIDE_RATING(4,33)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 38130, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) + ratings.excitement /= 2; + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 1, 1); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,40), 2, 1, 1); + + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 1, 1); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_virginia_reel(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 19; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,10), RIDE_RATING(1,90), RIDE_RATING(3,70)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 655360); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 110592, 29789, 59578); + ride_ratings_apply_65DDD1(&ratings, ride, 52012, 26075, 45749); + ride_ratings_apply_drops(&ratings, ride, 43690, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 22367); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xD20000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_splash_boats(rct_ride *ride) +{ + rating_tuple ratings; if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - ride->var_198 = 0; - sub_655FD6(ride); + ride->unreliability_factor = 15; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(1,50); - ratings.intensity = RIDE_RATING(0,90); - ratings.nausea = RIDE_RATING(0,00); + ride_ratings_set(&ratings, RIDE_RATING(1,46), RIDE_RATING(0,35), RIDE_RATING(0,30)); + ride_ratings_apply_length(&ratings, ride, 2000, 7208); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_max_speed(&ratings, ride, 797059, 655360, 301111); + ride_ratings_apply_duration(&ratings, ride, 500, 13107); + ride_ratings_apply_65DDD1(&ratings, ride, 22291, 20860, 4574); + ride_ratings_apply_drops(&ratings, ride, 87381, 93622, 62259); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 22367); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 6, 2, 2, 2); - // Apply length factor - int length = (ride->length[0] + ride->length[1] + ride->length[2] + ride->length[3]) >> 16; - ratings.excitement += (min(6000, length) * 873) >> 16; + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); - // Apply ? - unkRating = sub_65DDD1(ride); - ratings.excitement += (unkRating.excitement * 14860) >> 16; + ride->ratings = ratings; - // Apply ? - unkRating = sub_65E1C2(ride); - ratings.excitement += (unkRating.excitement * 5140) >> 16; - ratings.intensity += (unkRating.intensity * 6553) >> 16; - ratings.nausea += (unkRating.nausea * 4681) >> 16; + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; - // Apply ? - ratings.excitement += (sub_65E277() * 15657) >> 16; + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 27887) >> 16; +static void ride_ratings_calculate_mini_helicopters(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 12; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,60), RIDE_RATING(0,40), RIDE_RATING(0,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,15), RIDE_RATING(0,00)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_65DDD1(&ratings, ride, 14860, 0, 4574); + ride_ratings_apply_drops(&ratings, ride, 8738, 0, 0); + ride_ratings_apply_65E1C2(&ratings, ride, 12850, 6553, 4681); + ride_ratings_apply_65E277(&ratings, ride, 8946); + ride_ratings_apply_scenery(&ratings, ride, 8366); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xA00000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= 6 << 5; +} + +static void ride_ratings_calculate_lay_down_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 18; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,85), RIDE_RATING(1,15), RIDE_RATING(2,75)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 38130, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) { + ratings.excitement /= 4; + ratings.intensity /= 2; + ratings.nausea /= 2; + } + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) { + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0, 40), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + } + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_suspended_monorail(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,15), RIDE_RATING(0,23), RIDE_RATING(0, 8)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_train_length(&ratings, ride, 93622); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 70849, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 218453); + ride_ratings_apply_duration(&ratings, ride, 150, 21845); + ride_ratings_apply_65E1C2(&ratings, ride, 5140, 6553, 18724); + ride_ratings_apply_65E277(&ratings, ride, 12525); + ride_ratings_apply_scenery(&ratings, ride, 25098); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xAA0000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + int edx = sub_65E72D(ride); + if (((edx >> 8) & 0xFF) >= 4) + ride->excitement /= 4; + + ride->inversions &= 0x1F; + ride->inversions |= edx << 5; +} + +static void ride_ratings_calculate_reverser_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 19; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,40), RIDE_RATING(1,80), RIDE_RATING(1,70)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 655360); + + int unk = min(RCT2_GLOBAL(0x0138B5CC, uint16), 6) * 20; + ratings.excitement += unk; + ratings.intensity += unk; + ratings.nausea += unk; + + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 28672, 23831, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 43458, 45749); + ride_ratings_apply_drops(&ratings, ride, 40777, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 22367); + ride_ratings_apply_scenery(&ratings, ride, 11155); + + if (RCT2_GLOBAL(0x0138B5CC, uint16) < 1) + ratings.excitement /= 8; + + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xC80000, 2, 1, 1); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 1, 1); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_heartline_twister_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 18; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,40), RIDE_RATING(1,70), RIDE_RATING(1,65)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,20), RIDE_RATING(0,04)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 97418, 123987, 70849); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 44683, 89367); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 52150, 57186); + ride_ratings_apply_drops(&ratings, ride, 29127, 53052, 55705); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 34952, 35108); + ride_ratings_apply_65E277(&ratings, ride, 9841); + ride_ratings_apply_scenery(&ratings, ride, 3904); + + if ((ride->inversions & 0x1F) == 0) + ratings.excitement /= 4; + + ride_ratings_apply_num_drops_penalty(&ratings, ride, 1, 4, 1, 1); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_mini_golf(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 0; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,50), RIDE_RATING(0,90), RIDE_RATING(0,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_65DDD1(&ratings, ride, 14860, 0, 0); + ride_ratings_apply_65E1C2(&ratings, ride, 5140, 6553, 4681); + ride_ratings_apply_65E277(&ratings, ride, 15657); + ride_ratings_apply_scenery(&ratings, ride, 27887); // Apply golf holes factor ratings.excitement += (ride->holes & 0x1F) * 5; @@ -1382,7 +2914,7 @@ static void ride_ratings_calculate_mini_golf(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= sub_65E72D(ride) << 5; @@ -1391,7 +2923,7 @@ static void ride_ratings_calculate_mini_golf(rct_ride *ride) static void ride_ratings_calculate_first_aid(rct_ride *ride) { ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; } static void ride_ratings_calculate_circus_show(rct_ride *ride) @@ -1400,8 +2932,8 @@ static void ride_ratings_calculate_circus_show(rct_ride *ride) ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 9; - sub_655FD6(ride); + ride->unreliability_factor = 9; + set_unreliability_factor(ride); ratings.excitement = RIDE_RATING(2,10); ratings.intensity = RIDE_RATING(0,30); @@ -1413,20 +2945,383 @@ static void ride_ratings_calculate_circus_show(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 7 << 5; } +static void ride_ratings_calculate_ghost_train(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 12; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,00), RIDE_RATING(0,20), RIDE_RATING(0,03)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,15), RIDE_RATING(0,00)); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_65DDD1(&ratings, ride, 14860, 0, 11437); + ride_ratings_apply_drops(&ratings, ride, 8738, 0, 0); + ride_ratings_apply_65E1C2(&ratings, ride, 25700, 6553, 4681); + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 8366); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xB40000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_twister_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 15; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,50), RIDE_RATING(0,40), RIDE_RATING(0,30)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 32768, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) { + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0, 40), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + } + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_wooden_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 19; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,20), RIDE_RATING(2,60), RIDE_RATING(2,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 655360); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 40960, 34555, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 43458, 45749); + ride_ratings_apply_drops(&ratings, ride, 40777, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 22367); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,10), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x1720000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_side_friction_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 19; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,50), RIDE_RATING(2,00), RIDE_RATING(1,50)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 655360); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 28672, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 43458, 45749); + ride_ratings_apply_drops(&ratings, ride, 40777, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 22367); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 6, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x50000, 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xFA0000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_wild_mouse(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,80), RIDE_RATING(2,50), RIDE_RATING(2,10)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0, 8)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 655360); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 102400, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 29721, 43458, 45749); + ride_ratings_apply_drops(&ratings, ride, 40777, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 17893); + ride_ratings_apply_scenery(&ratings, ride, 5577); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 6, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x70000, 2, 2, 2); + ride_ratings_apply_max_lateral_g_penalty(&ratings, ride, FIXED_2DP(1,50), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xAA0000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_multi_dimension_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 18; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,75), RIDE_RATING(1,95), RIDE_RATING(4,79)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 38130, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) + ratings.excitement /= 4; + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 1, 1); + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,40), 2, 1, 1); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 1, 1); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_giga_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,85), RIDE_RATING(0,40), RIDE_RATING(0,35)); + ride_ratings_apply_length(&ratings, ride, 6000, 819); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 140434); + ride_ratings_apply_max_speed(&ratings, ride, 51366, 85019, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 400497); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 36864, 30384, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 28235, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 43690, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 16, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) { + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0, 40), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + } + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_roto_drop(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 24; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,80), RIDE_RATING(3,50), RIDE_RATING(3,50)); + + int lengthFactor = ((ride_get_total_length(ride) >> 16) * 209715) >> 16; + ratings.excitement += lengthFactor; + ratings.intensity += lengthFactor * 2; + ratings.nausea += lengthFactor * 2; + + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 25098); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_flying_saucers(rct_ride *ride) +{ + rating_tuple ratings; + + ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; + ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; + ride->unreliability_factor = 32; + set_unreliability_factor(ride); + + ratings.excitement = RIDE_RATING(2,40); + ratings.intensity = RIDE_RATING(0,55); + ratings.nausea = RIDE_RATING(0,39); + + if (ride->num_vehicles >= 4) + ratings.excitement += RIDE_RATING(0,40); + + ratings.excitement += ride->time_limit; + ratings.intensity += ride->time_limit / 2; + + if (ride->num_vehicles >= 4) + ratings.excitement += RIDE_RATING(0,40); + + ride_ratings_apply_scenery(&ratings, ride, 5577); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= 0 << 5; +} + static void ride_ratings_calculate_crooked_house(rct_ride *ride) { rating_tuple ratings; ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 5; - sub_655FD6(ride); + ride->unreliability_factor = 5; + set_unreliability_factor(ride); ratings.excitement = RIDE_RATING(2,15); ratings.intensity = RIDE_RATING(0,62); @@ -1438,31 +3333,224 @@ static void ride_ratings_calculate_crooked_house(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0xE0; } +static void ride_ratings_calculate_monorail_cycles(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 4; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,40), RIDE_RATING(0,20), RIDE_RATING(0,00)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,15), RIDE_RATING(0,00)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_65DDD1(&ratings, ride, 14860, 0, 4574); + ride_ratings_apply_drops(&ratings, ride, 8738, 0, 0); + ride_ratings_apply_65E1C2(&ratings, ride, 5140, 6553, 2340); + ride_ratings_apply_65E277(&ratings, ride, 8946); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x8C0000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_compact_inverted_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = ride->mode == RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE ? 31 : 21; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,15), RIDE_RATING(2,80), RIDE_RATING(3,20)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,42), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 30980, 55606); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 29552, 57186); + ride_ratings_apply_drops(&ratings, ride, 29127, 39009, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 15291, 35108); + ride_ratings_apply_65E277(&ratings, ride, 15657); + ride_ratings_apply_scenery(&ratings, ride, 8366); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,30), 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_water_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,70), RIDE_RATING(2,80), RIDE_RATING(2,10)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 20480, 23831, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 25700, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 9760); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 8, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x70000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 1, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + if (!(ride->special_track_elements & RIDE_ELEMENT_TUNNEL_SPLASH_OR_RAPIDS)) + ratings.excitement /= 8; + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_air_powered_vertical_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 28; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(4,13), RIDE_RATING(2,50), RIDE_RATING(2,80)); + ride_ratings_apply_length(&ratings, ride, 6000, 327); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,60), RIDE_RATING(0,05)); + ride_ratings_apply_max_speed(&ratings, ride, 509724, 364088, 320398); + ride_ratings_apply_gforces(&ratings, ride, 24576, 35746, 59578); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 21845, 11702); + ride_ratings_apply_65E277(&ratings, ride, 17893); + ride_ratings_apply_scenery(&ratings, ride, 11155); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 34, 2, 1, 1); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_inverted_hairpin_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 14; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(3,00), RIDE_RATING(2,65), RIDE_RATING(2,25)); + ride_ratings_apply_length(&ratings, ride, 6000, 873); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0, 8)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 364088, 655360); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 102400, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 29721, 43458, 45749); + ride_ratings_apply_drops(&ratings, ride, 40777, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 16705, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 17893); + ride_ratings_apply_scenery(&ratings, ride, 5577); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 8, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x70000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,10), 2, 2, 2); + ride_ratings_apply_max_lateral_g_penalty(&ratings, ride, FIXED_2DP(1,50), 2, 2, 2); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0xAA0000, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 3, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + static void ride_ratings_calculate_magic_carpet(rct_ride *ride) { rating_tuple ratings; ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 16; - sub_655FD6(ride); + ride->unreliability_factor = 16; + set_unreliability_factor(ride); - // Base ratings - ratings.excitement = RIDE_RATING(2,45); - ratings.intensity = RIDE_RATING(1,60); - ratings.nausea = RIDE_RATING(2,60); + ride_ratings_set(&ratings, RIDE_RATING(2,45), RIDE_RATING(1,60), RIDE_RATING(2,60)); - ratings.excitement += ride->var_0D0 * 10; - ratings.intensity += ride->var_0D0 * 20; - ratings.nausea += ride->var_0D0 * 20; + ratings.excitement += ride->operation_option * 10; + ratings.intensity += ride->operation_option * 20; + ratings.nausea += ride->operation_option * 20; - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 11155) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1470,31 +3558,89 @@ static void ride_ratings_calculate_magic_carpet(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 0 << 5; } +static void ride_ratings_calculate_submarine_ride(rct_ride *ride) +{ + rating_tuple ratings; + + ride->unreliability_factor = 7; + set_unreliability_factor(ride); + + // NOTE Fixed bug from original game, see boat ride. + + ride_ratings_set(&ratings, RIDE_RATING(2,20), RIDE_RATING(1,80), RIDE_RATING(1,40)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_scenery(&ratings, ride, 22310); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= 0 << 5; +} + +static void ride_ratings_calculate_river_rafts(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 12; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(1,45), RIDE_RATING(0,25), RIDE_RATING(0,34)); + ride_ratings_apply_length(&ratings, ride, 2000, 7208); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_max_speed(&ratings, ride, 531372, 655360, 301111); + ride_ratings_apply_duration(&ratings, ride, 500, 13107); + ride_ratings_apply_65DDD1(&ratings, ride, 22291, 20860, 4574); + ride_ratings_apply_drops(&ratings, ride, 78643, 93622, 62259); + ride_ratings_apply_65E277(&ratings, ride, 13420); + ride_ratings_apply_scenery(&ratings, ride, 11155); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + static void ride_ratings_calculate_enterprise(rct_ride *ride) { rating_tuple ratings; ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED; ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS; - ride->var_198 = 22; - sub_655FD6(ride); + ride->unreliability_factor = 22; + set_unreliability_factor(ride); // Base ratings ratings.excitement = RIDE_RATING(3,60); ratings.intensity = RIDE_RATING(4,55); ratings.nausea = RIDE_RATING(5,72); - ratings.excitement += ride->var_0D0; - ratings.intensity += ride->var_0D0 * 16; - ratings.nausea += ride->var_0D0 * 16; + ratings.excitement += ride->operation_option; + ratings.intensity += ride->operation_option * 16; + ratings.nausea += ride->operation_option * 16; - ratings.excitement += (ride_ratings_get_scenery_score(ride) * 19521) >> 16; + ride_ratings_apply_scenery(&ratings, ride, 19521); ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -1502,109 +3648,270 @@ static void ride_ratings_calculate_enterprise(rct_ride *ride) ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); - ride->var_14D |= 2; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; ride->inversions &= 0x1F; ride->inversions |= 3 << 5; } +static void ride_ratings_calculate_inverted_impulse_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 20; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(4,00), RIDE_RATING(3,00), RIDE_RATING(3,20)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,42), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 29789, 55606); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 29552, 57186); + ride_ratings_apply_drops(&ratings, ride, 29127, 39009, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 15291, 35108); + ride_ratings_apply_65E277(&ratings, ride, 15657); + ride_ratings_apply_scenery(&ratings, ride, 9760); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 20, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_mini_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 13; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,55), RIDE_RATING(2,40), RIDE_RATING(1,85)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 20480, 23831, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 25700, 30583, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 9760); + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 12, 2, 2, 2); + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0x70000, 2, 2, 2); + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, FIXED_2DP(0,50), 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_mine_ride(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 16; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,75), RIDE_RATING(1,00), RIDE_RATING(1,80)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 40960, 29789, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 29721, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 19275, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 21472); + ride_ratings_apply_scenery(&ratings, ride, 16732); + ride_ratings_apply_first_length_penalty(&ratings, ride, 0x10E0000, 2, 2, 2); + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + +static void ride_ratings_calculate_lim_launched_roller_coaster(rct_ride *ride) +{ + rating_tuple ratings; + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) + return; + + ride->unreliability_factor = 25; + set_unreliability_factor(ride); + + ride_ratings_set(&ratings, RIDE_RATING(2,90), RIDE_RATING(1,50), RIDE_RATING(2,20)); + ride_ratings_apply_length(&ratings, ride, 6000, 764); + ride_ratings_apply_synchronisation(&ratings, ride, RIDE_RATING(0,40), RIDE_RATING(0,05)); + ride_ratings_apply_train_length(&ratings, ride, 187245); + ride_ratings_apply_max_speed(&ratings, ride, 44281, 88562, 35424); + ride_ratings_apply_average_speed(&ratings, ride, 291271, 436906); + ride_ratings_apply_duration(&ratings, ride, 150, 26214); + ride_ratings_apply_gforces(&ratings, ride, 24576, 35746, 49648); + ride_ratings_apply_65DDD1(&ratings, ride, 26749, 34767, 45749); + ride_ratings_apply_drops(&ratings, ride, 29127, 46811, 49152); + ride_ratings_apply_65E1C2(&ratings, ride, 15420, 32768, 35108); + ride_ratings_apply_65E277(&ratings, ride, 20130); + ride_ratings_apply_scenery(&ratings, ride, 6693); + + if ((ride->inversions & 0x1F) == 0) + ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 10, 2, 2, 2); + + ride_ratings_apply_max_speed_penalty(&ratings, ride, 0xA0000, 2, 2, 2); + + if ((ride->inversions & 0x1F) == 0) { + ride_ratings_apply_max_negative_g_penalty(&ratings, ride, 10, 2, 2, 2); + ride_ratings_apply_num_drops_penalty(&ratings, ride, 2, 2, 2, 2); + } + + ride_ratings_apply_intensity_penalty(&ratings); + ride_ratings_apply_adjustments(ride, &ratings); + + ride->ratings = ratings; + + ride->upkeep_cost = ride_compute_upkeep(ride); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + + ride->inversions &= 0x1F; + ride->inversions |= sub_65E72D(ride) << 5; +} + #pragma endregion #pragma region Ride rating calculation function table // rct2: 0x0097E050 static const ride_ratings_calculation ride_ratings_calculate_func_table[91] = { - NULL, // SPIRAL_ROLLER_COASTER - NULL, // STAND_UP_ROLLER_COASTER - NULL, // SUSPENDED_SWINGING_COASTER - NULL, // INVERTED_ROLLER_COASTER - NULL, // JUNIOR_ROLLER_COASTER - NULL, // MINIATURE_RAILWAY - NULL, // MONORAIL - NULL, // MINI_SUSPENDED_COASTER - NULL, // BUMPER_BOATS - NULL, // WOODEN_WILD_MOUSE - NULL, // STEEPLECHASE - NULL, // CAR_RIDE - NULL, // LAUNCHED_FREEFALL - NULL, // BOBSLEIGH_COASTER - NULL, // OBSERVATION_TOWER - NULL, // LOOPING_ROLLER_COASTER - NULL, // DINGHY_SLIDE - ride_ratings_calculate_mine_train_coaster, // MINE_TRAIN_COASTER - NULL, // CHAIRLIFT - NULL, // CORKSCREW_ROLLER_COASTER - ride_ratings_calculate_maze, // MAZE - ride_ratings_calculate_spiral_slide, // SPIRAL_SLIDE - NULL, // GO_KARTS - NULL, // LOG_FLUME - NULL, // RIVER_RAPIDS - NULL, // BUMPER_CARS - ride_ratings_calculate_pirate_ship, // PIRATE_SHIP - ride_ratings_calculate_inverter_ship, // SWINGING_INVERTER_SHIP - ride_ratings_calculate_food_stall, // FOOD_STALL - NULL, // 1D - ride_ratings_calculate_drink_stall, // DRINK_STALL - NULL, // 1F - ride_ratings_calculate_shop, // SHOP - ride_ratings_calculate_merry_go_round, // MERRY_GO_ROUND - NULL, // 22 - ride_ratings_calculate_information_kiosk, // INFORMATION_KIOSK - ride_ratings_calculate_bathroom, // BATHROOM - ride_ratings_calculate_ferris_wheel, // FERRIS_WHEEL - ride_ratings_calculate_motion_simulator, // MOTION_SIMULATOR - ride_ratings_calculate_3d_cinema, // 3D_CINEMA - ride_ratings_calculate_top_spin, // TOP_SPIN - ride_ratings_calculate_space_rings, // SPACE_RINGS - NULL, // REVERSE_FREEFALL_COASTER - ride_ratings_calculate_elevator, // ELEVATOR - NULL, // VERTICAL_DROP_ROLLER_COASTER - ride_ratings_calculate_atm, // ATM - ride_ratings_calculate_twist, // TWIST - ride_ratings_calculate_haunted_house, // HAUNTED_HOUSE - ride_ratings_calculate_first_aid, // FIRST_AID - ride_ratings_calculate_circus_show, // CIRCUS_SHOW - NULL, // GHOST_TRAIN - NULL, // TWISTER_ROLLER_COASTER - NULL, // WOODEN_ROLLER_COASTER - NULL, // SIDE_FRICTION_ROLLER_COASTER - NULL, // WILD_MOUSE - NULL, // MULTI_DIMENSION_ROLLER_COASTER - NULL, // 38 - NULL, // FLYING_ROLLER_COASTER - NULL, // 3A - NULL, // VIRGINIA_REEL - NULL, // SPLASH_BOATS - NULL, // MINI_HELICOPTERS - NULL, // LAY_DOWN_ROLLER_COASTER - NULL, // SUSPENDED_MONORAIL - NULL, // 40 - NULL, // REVERSER_ROLLER_COASTER - NULL, // HEARTLINE_TWISTER_COASTER - ride_ratings_calculate_mini_golf, // MINI_GOLF - NULL, // GIGA_COASTER - NULL, // ROTO_DROP - NULL, // FLYING_SAUCERS - ride_ratings_calculate_crooked_house, // CROOKED_HOUSE - NULL, // MONORAIL_CYCLES - NULL, // COMPACT_INVERTED_COASTER - NULL, // WATER_COASTER - NULL, // AIR_POWERED_VERTICAL_COASTER - NULL, // INVERTED_HAIRPIN_COASTER - ride_ratings_calculate_magic_carpet, // MAGIC_CARPET - NULL, // SUBMARINE_RIDE - NULL, // RIVER_RAFTS - NULL, // 50 - ride_ratings_calculate_enterprise, // ENTERPRISE - NULL, // 52 - NULL, // 53 - NULL, // 54 - NULL, // 55 - NULL, // INVERTED_IMPULSE_COASTER - NULL, // MINI_ROLLER_COASTER - NULL, // MINE_RIDE - NULL, // LIM_LAUNCHED_ROLLER_COASTER - NULL, // 90 + ride_ratings_calculate_spiral_roller_coaster, // SPIRAL_ROLLER_COASTER + ride_ratings_calculate_stand_up_roller_coaster, // STAND_UP_ROLLER_COASTER + ride_ratings_calculate_suspended_swinging_coaster, // SUSPENDED_SWINGING_COASTER + ride_ratings_calculate_inverted_roller_coaster, // INVERTED_ROLLER_COASTER + ride_ratings_calculate_junior_roller_coaster, // JUNIOR_ROLLER_COASTER + ride_ratings_calculate_miniature_railway, // MINIATURE_RAILWAY + ride_ratings_calculate_monorail, // MONORAIL + ride_ratings_calculate_mini_suspended_coaster, // MINI_SUSPENDED_COASTER + ride_ratings_calculate_boat_ride, // BOAT_RIDE + ride_ratings_calculate_wooden_wild_mouse, // WOODEN_WILD_MOUSE + ride_ratings_calculate_steeplechase, // STEEPLECHASE + ride_ratings_calculate_car_ride, // CAR_RIDE + ride_ratings_calculate_launched_freefall, // LAUNCHED_FREEFALL + ride_ratings_calculate_bobsleigh_coaster, // BOBSLEIGH_COASTER + ride_ratings_calculate_observation_tower, // OBSERVATION_TOWER + ride_ratings_calculate_looping_roller_coaster, // LOOPING_ROLLER_COASTER + ride_ratings_calculate_dinghy_slide, // DINGHY_SLIDE + ride_ratings_calculate_mine_train_coaster, // MINE_TRAIN_COASTER + ride_ratings_calculate_chairlift, // CHAIRLIFT + ride_ratings_calculate_corkscrew_roller_coaster, // CORKSCREW_ROLLER_COASTER + ride_ratings_calculate_maze, // MAZE + ride_ratings_calculate_spiral_slide, // SPIRAL_SLIDE + ride_ratings_calculate_go_karts, // GO_KARTS + ride_ratings_calculate_log_flume, // LOG_FLUME + ride_ratings_calculate_river_rapids, // RIVER_RAPIDS + ride_ratings_calculate_dodgems, // DODGEMS + ride_ratings_calculate_pirate_ship, // PIRATE_SHIP + ride_ratings_calculate_inverter_ship, // SWINGING_INVERTER_SHIP + ride_ratings_calculate_food_stall, // FOOD_STALL + ride_ratings_calculate_food_stall, // 1D + ride_ratings_calculate_drink_stall, // DRINK_STALL + ride_ratings_calculate_drink_stall, // 1F + ride_ratings_calculate_shop, // SHOP + ride_ratings_calculate_merry_go_round, // MERRY_GO_ROUND + ride_ratings_calculate_shop, // 22 + ride_ratings_calculate_information_kiosk, // INFORMATION_KIOSK + ride_ratings_calculate_toilets, // TOILETS + ride_ratings_calculate_ferris_wheel, // FERRIS_WHEEL + ride_ratings_calculate_motion_simulator, // MOTION_SIMULATOR + ride_ratings_calculate_3d_cinema, // 3D_CINEMA + ride_ratings_calculate_top_spin, // TOP_SPIN + ride_ratings_calculate_space_rings, // SPACE_RINGS + ride_ratings_calculate_reverse_freefall_coaster, // REVERSE_FREEFALL_COASTER + ride_ratings_calculate_lift, // LIFT + ride_ratings_calculate_vertical_drop_roller_coaster, // VERTICAL_DROP_ROLLER_COASTER + ride_ratings_calculate_cash_machine, // CASH_MACHINE + ride_ratings_calculate_twist, // TWIST + ride_ratings_calculate_haunted_house, // HAUNTED_HOUSE + ride_ratings_calculate_first_aid, // FIRST_AID + ride_ratings_calculate_circus_show, // CIRCUS_SHOW + ride_ratings_calculate_ghost_train, // GHOST_TRAIN + ride_ratings_calculate_twister_roller_coaster, // TWISTER_ROLLER_COASTER + ride_ratings_calculate_wooden_roller_coaster, // WOODEN_ROLLER_COASTER + ride_ratings_calculate_side_friction_roller_coaster, // SIDE_FRICTION_ROLLER_COASTER + ride_ratings_calculate_wild_mouse, // WILD_MOUSE + ride_ratings_calculate_multi_dimension_roller_coaster, // MULTI_DIMENSION_ROLLER_COASTER + ride_ratings_calculate_multi_dimension_roller_coaster, // 38 + ride_ratings_calculate_flying_roller_coaster, // FLYING_ROLLER_COASTER + ride_ratings_calculate_flying_roller_coaster, // 3A + ride_ratings_calculate_virginia_reel, // VIRGINIA_REEL + ride_ratings_calculate_splash_boats, // SPLASH_BOATS + ride_ratings_calculate_mini_helicopters, // MINI_HELICOPTERS + ride_ratings_calculate_lay_down_roller_coaster, // LAY_DOWN_ROLLER_COASTER + ride_ratings_calculate_suspended_monorail, // SUSPENDED_MONORAIL + ride_ratings_calculate_lay_down_roller_coaster, // 40 + ride_ratings_calculate_reverser_roller_coaster, // REVERSER_ROLLER_COASTER + ride_ratings_calculate_heartline_twister_coaster, // HEARTLINE_TWISTER_COASTER + ride_ratings_calculate_mini_golf, // MINI_GOLF + ride_ratings_calculate_giga_coaster, // GIGA_COASTER + ride_ratings_calculate_roto_drop, // ROTO_DROP + ride_ratings_calculate_flying_saucers, // FLYING_SAUCERS + ride_ratings_calculate_crooked_house, // CROOKED_HOUSE + ride_ratings_calculate_monorail_cycles, // MONORAIL_CYCLES + ride_ratings_calculate_compact_inverted_coaster, // COMPACT_INVERTED_COASTER + ride_ratings_calculate_water_coaster, // WATER_COASTER + ride_ratings_calculate_air_powered_vertical_coaster, // AIR_POWERED_VERTICAL_COASTER + ride_ratings_calculate_inverted_hairpin_coaster, // INVERTED_HAIRPIN_COASTER + ride_ratings_calculate_magic_carpet, // MAGIC_CARPET + ride_ratings_calculate_submarine_ride, // SUBMARINE_RIDE + ride_ratings_calculate_river_rafts, // RIVER_RAFTS + NULL, // 50 + ride_ratings_calculate_enterprise, // ENTERPRISE + NULL, // 52 + NULL, // 53 + NULL, // 54 + NULL, // 55 + ride_ratings_calculate_inverted_impulse_coaster, // INVERTED_IMPULSE_COASTER + ride_ratings_calculate_mini_roller_coaster, // MINI_ROLLER_COASTER + ride_ratings_calculate_mine_ride, // MINE_RIDE + NULL, // 59 + ride_ratings_calculate_lim_launched_roller_coaster, // LIM_LAUNCHED_ROLLER_COASTER }; -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/ride/ride_ratings.h b/src/ride/ride_ratings.h index 5baa99e2e9..467b2c23a8 100644 --- a/src/ride/ride_ratings.h +++ b/src/ride/ride_ratings.h @@ -25,5 +25,6 @@ #include "ride.h" void ride_ratings_update_all(); +int sub_6C6402(rct_map_element **mapElement, int *x, int *y, int *z); #endif \ No newline at end of file diff --git a/src/ride/station.c b/src/ride/station.c index 398c98892e..c982a44757 100644 --- a/src/ride/station.c +++ b/src/ride/station.c @@ -89,7 +89,8 @@ static void ride_update_station_bumpercar(rct_ride *ride, int stationIndex) { int i, dx, dl, dh; rct_vehicle *vehicle; - + // Change of station depart flag should really call invalidate_station_start + // but since bumpercars do not have station lights there is no point. if ( ride->status == RIDE_STATUS_CLOSED || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) @@ -128,7 +129,7 @@ static void ride_update_station_bumpercar(rct_ride *ride, int stationIndex) // Begin the match ride->lifecycle_flags |= RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; ride->station_depart[stationIndex] |= STATION_DEPART_FLAG; - ride->var_14D |= 12; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; } } @@ -142,21 +143,24 @@ static void ride_update_station_normal(rct_ride *ride, int stationIndex) time = ride->station_depart[stationIndex] & STATION_DEPART_MASK; if ( - (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) && + (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) || (ride->status == RIDE_STATUS_CLOSED && ride->num_riders == 0) ) { if (time != 0 && time != 127 && !(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 7)) time--; ride->station_depart[stationIndex] = time; + ride_invalidate_station_start(ride, stationIndex, 0); } else { if (time == 0) { ride->station_depart[stationIndex] |= STATION_DEPART_FLAG; + ride_invalidate_station_start(ride, stationIndex, 1); } else { if (time != 127 && !(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 31)) time--; ride->station_depart[stationIndex] = time; + ride_invalidate_station_start(ride, stationIndex, 0); } } } @@ -175,7 +179,10 @@ static void ride_update_station_race(rct_ride *ride, int stationIndex) ride->status == RIDE_STATUS_CLOSED || (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) ) { - ride->station_depart[stationIndex] &= ~STATION_DEPART_FLAG; + if (ride->station_depart[stationIndex] & STATION_DEPART_FLAG){ + ride->station_depart[stationIndex] &= ~STATION_DEPART_FLAG; + ride_invalidate_station_start(ride, stationIndex, 0); + } return; } @@ -188,12 +195,15 @@ static void ride_update_station_race(rct_ride *ride, int stationIndex) if (vehicle->num_peeps != 0) { peep = &(g_sprite_list[vehicle->peep[0]].peep); ride->race_winner = peep->sprite_index; - ride->var_14D |= 12; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; } // Race is over ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; - ride->station_depart[stationIndex] &= ~STATION_DEPART_FLAG; + if (ride->station_depart[stationIndex] & STATION_DEPART_FLAG){ + ride->station_depart[stationIndex] &= ~STATION_DEPART_FLAG; + ride_invalidate_station_start(ride, stationIndex, 0); + } return; } } @@ -205,7 +215,10 @@ static void ride_update_station_race(rct_ride *ride, int stationIndex) for (i = 0; i < ride->num_vehicles; i++) { vehicle = &(g_sprite_list[ride->vehicles[i]].vehicle); if (vehicle->status != VEHICLE_STATUS_WAITING_TO_DEPART && vehicle->status != VEHICLE_STATUS_DEPARTING) { - ride->station_depart[stationIndex] &= ~STATION_DEPART_FLAG; + if (ride->station_depart[stationIndex] & STATION_DEPART_FLAG){ + ride->station_depart[stationIndex] &= ~STATION_DEPART_FLAG; + ride_invalidate_station_start(ride, stationIndex, 0); + } return; } } @@ -213,8 +226,11 @@ static void ride_update_station_race(rct_ride *ride, int stationIndex) // Begin the race ride_race_init_vehicle_speeds(ride); ride->lifecycle_flags |= RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; - ride->station_depart[stationIndex] |= STATION_DEPART_FLAG; - ride->var_14D |= 12; + if (!(ride->station_depart[stationIndex] & STATION_DEPART_FLAG)){ + ride->station_depart[stationIndex] |= STATION_DEPART_FLAG; + ride_invalidate_station_start(ride, stationIndex, 1); + } + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; } } @@ -228,17 +244,15 @@ static void ride_race_init_vehicle_speeds(rct_ride *ride) { rct_ride_type *rideEntry; rct_vehicle *vehicle; - uint8 *unk; int i; for (i = 0; i < ride->num_vehicles; i++) { vehicle = &g_sprite_list[ride->vehicles[i]].vehicle; vehicle->var_48 &= ~(1 << 6); - rideEntry = GET_RIDE_ENTRY(vehicle->var_D6); - unk = (uint8*)((int)rideEntry + (vehicle->var_31 * 0x65)); + rideEntry = GET_RIDE_ENTRY(vehicle->ride_subtype); - vehicle->speed = (scenario_rand() & 16) - 8 + RCT2_GLOBAL(unk + 0x76, uint8); + vehicle->speed = (scenario_rand() & 16) - 8 + rideEntry->vehicles[vehicle->vehicle_type].var_5C; if (vehicle->num_peeps != 0) { rct_peep *peep = &g_sprite_list[vehicle->peep[0]].peep; @@ -277,6 +291,10 @@ static void ride_invalidate_station_start(rct_ride *ride, int stationIndex, int y = (ride->station_starts[stationIndex] >> 8) * 32; mapElement = ride_get_station_start_track_element(ride, stationIndex); + // If no station track found return + if (mapElement == NULL) + return; + mapElement->properties.track.sequence &= 0x7F; if (dl != 0) mapElement->properties.track.sequence |= 0x80; @@ -294,16 +312,13 @@ rct_map_element *ride_get_station_start_track_element(rct_ride *ride, int statio y = ride->station_starts[stationIndex] >> 8; z = ride->station_heights[stationIndex]; - // Get first element of the tile - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); - // Find the station track element + mapElement = map_get_first_element_at(x, y); do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_TRACK && z == mapElement->base_height) + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK && z == mapElement->base_height) return mapElement; - mapElement++; - } while (!((mapElement - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); return NULL; } @@ -312,16 +327,12 @@ rct_map_element *ride_get_station_exit_element(rct_ride *ride, int x, int y, int { rct_map_element *mapElement; - // Get first element of the tile - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); - // Find the station track element + mapElement = map_get_first_element_at(x, y); do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_ENTRANCE && z == mapElement->base_height) + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE && z == mapElement->base_height) return mapElement; - - mapElement++; - } while (!((mapElement - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); return NULL; -} \ No newline at end of file +} diff --git a/src/ride/track.c b/src/ride/track.c index 9ef270d977..0b90178d55 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -19,17 +19,32 @@ *****************************************************************************/ #include "../addresses.h" -#include "../platform/osinterface.h" +#include "../audio/audio.h" +#include "../config.h" +#include "../game.h" +#include "../interface/viewport.h" +#include "../localisation/localisation.h" +#include "../platform/platform.h" +#include "../rct1.h" #include "../util/sawyercoding.h" #include "../util/util.h" +#include "../world/park.h" +#include "../world/scenery.h" +#include "../world/footpath.h" +#include "../windows/error.h" +#include "ride_ratings.h" #include "ride.h" #include "track.h" +#include "track_data.h" /** * * rct2: 0x00997C9D */ -const rct_trackdefinition gTrackDefinitions[] = { +const rct_trackdefinition *gTrackDefinitions = (rct_trackdefinition*)0x00997C9D; + +// TODO This table is incorrect or at least missing 69 elements. There should be 256 in total! +const rct_trackdefinition gTrackDefinitions_INCORRECT[] = { // TYPE VANGLE END VANGLE START BANK END BANK START SPECIAL { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_END_STATION @@ -220,19 +235,257 @@ const rct_trackdefinition gTrackDefinitions[] = { { TRACK_HALF_LOOP_2, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_HALF_LOOP_DOWN }, // ELEM_LEFT_LARGE_HALF_LOOP_DOWN }; +static bool track_save_should_select_scenery_around(int rideIndex, rct_map_element *mapElement); +static void track_save_select_nearby_scenery_for_tile(int rideIndex, int cx, int cy); +static void track_save_add_map_element(int mapElementSelectType, int x, int y, rct_map_element *mapElement); + +uint32* sub_6AB49A(rct_object_entry* entry){ + rct_object_entry* object_list_entry = object_list_find(entry); + + if (object_list_entry == NULL) return NULL; + + // Return the address of the last value of the list entry + return (((uint32*)object_get_next(object_list_entry)) - 1); +} + +static void get_track_idx_path(char *outPath) +{ + platform_get_user_directory(outPath, NULL); + strcat(outPath, "tracks.idx"); +} + +static void track_list_query_directory(int *outTotalFiles){ + int enumFileHandle; + file_info enumFileInfo; + + *outTotalFiles = 0; + + // Enumerate through each track in the directory + enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); + if (enumFileHandle == INVALID_HANDLE) + return; + + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { + (*outTotalFiles)++; + } + platform_enumerate_files_end(enumFileHandle); +} + +static int track_list_cache_save(int fileCount, uint8* track_list_cache, uint32 track_list_size){ + char path[MAX_PATH]; + FILE *file; + + log_verbose("saving track list cache (tracks.idx)"); + get_track_idx_path(path); + file = fopen(path, "wb"); + if (file == NULL) { + log_error("Failed to save %s", path); + return 0; + } + + fwrite(&fileCount, sizeof(int), 1, file); + fwrite(track_list_cache, track_list_size, 1, file); + uint8 last_entry = 0xFE; + fwrite(&last_entry, 1, 1, file); + fclose(file); + return 1; +} + +static uint8* track_list_cache_load(int totalFiles){ + char path[MAX_PATH]; + FILE *file; + + log_verbose("loading track list cache (tracks.idx)"); + get_track_idx_path(path); + file = fopen(path, "rb"); + if (file == NULL) { + log_error("Failed to load %s", path); + return 0; + } + + uint8* track_list_cache; + uint32 fileCount; + // Remove 4 for the file count variable + long track_list_size = fsize(file) - 4; + + if (track_list_size < 0) return 0; + + fread(&fileCount, 4, 1, file); + + if (fileCount != totalFiles){ + log_verbose("Track file count is different."); + return 0; + } + + track_list_cache = malloc(track_list_size); + fread(track_list_cache, track_list_size, 1, file); + return track_list_cache; +} + +void track_list_populate(ride_list_item item, uint8* track_list_cache){ + uint8* track_pointer = track_list_cache; + + uint8 cur_track_entry_index = 0; + for (uint8 track_type = *track_pointer++; track_type != 0xFE; + track_pointer += strlen(track_pointer) + 1, + track_type = *track_pointer++){ + rct_object_entry* track_object = (rct_object_entry*)track_pointer; + track_pointer += sizeof(rct_object_entry); + + if (track_type != item.type){ + continue; + } + + uint8 entry_type, entry_index; + if (item.entry_index != 0xFF){ + + if (!find_object_in_entry_group(track_object, &entry_type, &entry_index))continue; + + if (item.entry_index != entry_index)continue; + } + else{ + if (find_object_in_entry_group(track_object, &entry_type, &entry_index)){ + if (GET_RIDE_ENTRY(entry_index)->flags & + (RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME | + RIDE_ENTRY_FLAG_SEPERATE_RIDE)) + continue; + } + else{ + uint32* esi = sub_6AB49A(track_object); + if (esi == NULL) continue; + if (*esi & 0x1000000)continue; + } + } + + // If cur_track_entry_index is greater than max number of tracks + if (cur_track_entry_index >= 1000){ + RCT2_GLOBAL(0xF635ED, uint8) |= 1; + break; + } + + uint8 track_entry_index = 0; + uint8 isBelow = 0; + for (; track_entry_index != cur_track_entry_index; track_entry_index++){ + if (strcicmp(track_pointer, &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128]) < 0){ + isBelow = 1; + break; + } + } + + if (isBelow == 1){ + memmove( + &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128 + 128], + &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128], + (cur_track_entry_index - track_entry_index) * 128); + } + + strcpy(&RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128], track_pointer); + cur_track_entry_index++; + } + + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[cur_track_entry_index * 128] = '\0'; + free(track_list_cache); +} + /** * * rct2: 0x006CED50 */ void track_load_list(ride_list_item item) { - RCT2_CALLPROC_X(0x006CED50, 0, 0, 0, *((uint16*)&item), 0, 0, 0); + RCT2_GLOBAL(0xF635ED, uint8) = 0; + + if (item.type < 0x80){ + rct_ride_type* ride_type = gRideTypeList[item.entry_index]; + if (!(ride_type->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE)){ + item.entry_index = 0xFF; + } + } + + int totalFiles; + + track_list_query_directory(&totalFiles); + + uint8* track_list_cache; + + if (item.type == 0xFC || !(track_list_cache = track_list_cache_load(totalFiles))){ + uint8* new_track_file; + + new_track_file = malloc(0x40000); + + uint8* new_file_pointer = new_track_file; + file_info enumFileInfo; + + int enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); + if (enumFileHandle == INVALID_HANDLE) + return; + + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { + if (new_file_pointer > new_track_file + 0x3FF00)break; + + char path[MAX_PATH]; + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), enumFileInfo.path); + + rct_track_td6* loaded_track = load_track_design(path); + if (loaded_track){ + *new_file_pointer++ = loaded_track->type; + } + else{ + *new_file_pointer++ = 0xFF; + // Garbage object + new_file_pointer += sizeof(rct_object_entry); + // Empty string + *new_file_pointer++ = '\0'; + // Unsure why it previously didn't continue on load fail?? + continue; + } + memcpy(new_file_pointer, &loaded_track->vehicle_object, sizeof(rct_object_entry)); + new_file_pointer += sizeof(rct_object_entry); + + int file_name_length = strlen(enumFileInfo.path); + strcpy(new_file_pointer, enumFileInfo.path); + new_file_pointer += file_name_length + 1; + } + platform_enumerate_files_end(enumFileHandle); + + if (!track_list_cache_save(totalFiles, new_track_file, new_file_pointer - new_track_file)){ + log_error("Track list failed to save."); + return; + } + free(new_track_file); + + track_list_cache = track_list_cache_load(totalFiles); + if (!track_list_cache){ + log_error("Track list failed to load after new save"); + return; + } + } + + track_list_populate(item, track_list_cache); + free(track_list_cache); } -static void read(void *dst, void **src, int length) +static void read(void *dst, char **src, int length) { memcpy(dst, *src, length); - *((char**)src) += length; + *src += length; +} + +/* rct2: 0x00677530 + * Returns 1 if it has booster track elements + */ +uint8 td4_track_has_boosters(rct_track_td6* track_design, uint8* track_elements){ + if (track_design->type == RCT1_RIDE_TYPE_HEDGE_MAZE) + return 0; + + rct_track_element* track_element = (rct_track_element*)track_elements; + + for (; track_element->type != 0xFF; track_element++){ + if (track_element->type == RCT1_TRACK_ELEM_BOOSTER) + return 1; + } + + return 0; } /** @@ -240,30 +493,28 @@ static void read(void *dst, void **src, int length) * rct2: 0x0067726A * path: 0x0141EF68 */ -int sub_67726A(const char *path) +rct_track_td6* load_track_design(const char *path) { FILE *fp; long fpLength; - const char *ch; - char trackFilename[MAX_PATH], *fpBuffer, *decoded, *src, *dst; + char *fpBuffer, *decoded, *src; int i, decodedLength; uint8* edi; RCT2_GLOBAL(0x009AAC54, uint8) = 1; - // Get filename - ch = strrchr(path, '\\'); - ch = ch == NULL ? path : ch + 1; - dst = trackFilename; - while (*ch != 0 && *ch != '.') { - *dst++ = *ch++; - } - *dst = 0; - fp = fopen(path, "rb"); if (fp == NULL) return 0; + char* track_name_pointer = (char*)path; + while (*track_name_pointer++ != '\0'); + while (*--track_name_pointer != '\\'); + char* default_name = RCT2_ADDRESS(0x009E3504, char); + // Copy the track name for use as the default name of this ride + while (*++track_name_pointer != '.')*default_name++ = *track_name_pointer; + *default_name++ = '\0'; + // Read whole file into a buffer fpLength = fsize(fp); fpBuffer = malloc(fpLength); @@ -272,7 +523,10 @@ int sub_67726A(const char *path) // Validate the checksum // Not the same checksum algorithm as scenarios and saved games - // sub_6770C1(); + if (!sawyercoding_validate_track_checksum(fpBuffer, fpLength)){ + log_error("Track checksum failed."); + return 0; + } // Decode the track data decoded = malloc(0x10000); @@ -280,100 +534,1643 @@ int sub_67726A(const char *path) realloc(decoded, decodedLength); free(fpBuffer); + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); // Read decoded data src = decoded; - memset((void*)0x009D81D8, 0, 67); - read((void*)0x009D8178, &src, 32); + // Clear top of track_design as this is not loaded from the td4 files + memset(&track_design->track_spine_colour, 0, 67); + // Read start of track_design + read(track_design, &src, 32); - uint8 al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; - if (al >= 2) - read((void*)0x009D8198, &src, 40); + uint8 version = track_design->version_and_colour_scheme >> 2; - read((void*)0x009D81C0, &src, 24); - al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; - if (al != 0) - read((void*)0x009D81D8, &src, al == 1 ? 140 : 67); - - read((void*)0x009D821B, &src, 24572); - al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; - if (al < 2) { - if (RCT2_GLOBAL(0x009D8178, uint8) == 20) { - edi = (uint8*)0x009D821B; - while (*edi != 0) { - edi += 4; - } - edi += 4; - memset(edi, 255, (uint8*)0x009DE217 - edi); - } else { - edi = (uint8*)0x009D821B; - while (*edi != 255) { - edi += 2; - } - edi++; - memset(edi, 255, (uint8*)0x009DE217 - edi); - } + if (version > 2){ + free(decoded); + return NULL; } + + // In td6 there are 32 sets of two byte vehicle colour specifiers + // In td4 there are 12 sets so the remaining 20 need to be read. + if (version == 2) + read(&track_design->vehicle_colours[12], &src, 40); + + read(&track_design->pad_48, &src, 24); + + // In td4 (version AA/CF) and td6 both start actual track data at 0xA3 + if (version > 0) + read(&track_design->track_spine_colour, &src, version == 1 ? 140 : 67); + + uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + // Read the actual track data. + read(track_elements, &src, 24572); + + uint8* final_track_element_location = track_elements + 24572; free(decoded); - // - al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; - if (al > 2) - return 0; + // td4 files require some work to be recognised as td6. + if (version < 2) { - if (al <= 1) { - edi = (uint8*)0x009D8180; - for (i = 0; i < 67; i++) - *edi++ = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; + // Set any element passed the tracks to 0xFF + if (track_design->type == RIDE_TYPE_MAZE) { + rct_maze_element* maze_element = (rct_maze_element*)track_elements; + while (maze_element->all != 0) { + maze_element++; + } + maze_element++; + memset(maze_element, 255, final_track_element_location - (uint8*)maze_element); + } + else { + rct_track_element* track_element = (rct_track_element*)track_elements; + while (track_element->type != 255) { + track_element++; + } + memset(((uint8*)track_element) + 1, 255, final_track_element_location - (uint8*)track_element); + + } - edi = (uint8*)0x009D81D8; - for (i = 0; i < 12; i++) - *edi++ = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; + // Edit the colours to use the new versions + // Unsure why it is 67 + edi = (uint8*)&track_design->vehicle_colours; + for (i = 0; i < 67; i++, edi++) + *edi = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; - RCT2_GLOBAL(0x009D81D2, uint8) >>= 1; - if (!RCT2_CALLPROC_X(0x00677530, 0, 0, 0, 0, 0, 0, 0)) - RCT2_GLOBAL(0x009D8178, uint8) = 255; + // Edit the colours to use the new versions + edi = (uint8*)&track_design->track_spine_colour; + for (i = 0; i < 12; i++, edi++) + *edi = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; - if (RCT2_GLOBAL(0x009D8178, uint8) == 4) - RCT2_GLOBAL(0x009D8178, uint8) = 255; + // Highest drop height is 1bit = 3/4 a meter in td6 + // Highest drop height is 1bit = 1/3 a meter in td4 + // Not sure if this is correct?? + track_design->highest_drop_height >>= 1; - if (RCT2_GLOBAL(0x009D8178, uint8) == 0) - RCT2_GLOBAL(0x009D8178, uint8) = 52; + // If it has boosters then sadly track has to be discarded. + if (td4_track_has_boosters(track_design, track_elements)) + track_design->type = RIDE_TYPE_NULL; - if (RCT2_GLOBAL(0x009D8178, uint8) == 19) { - if (RCT2_GLOBAL(0x009D817E, uint8) == 3) - RCT2_GLOBAL(0x009D817E, uint8) = 35; - if (RCT2_GLOBAL(0x009D8179, uint8) == 79) { - if (RCT2_GLOBAL(0x009D817E, uint8) == 2) - RCT2_GLOBAL(0x009D817E, uint8) = 1; + if (track_design->type == RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER) + track_design->type = RIDE_TYPE_NULL; + + if (track_design->type == RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER) + track_design->type = RIDE_TYPE_WOODEN_ROLLER_COASTER; + + if (track_design->type == RIDE_TYPE_CORKSCREW_ROLLER_COASTER) { + if (track_design->ride_mode == RCT1_RIDE_MODE_POWERED_LAUNCH) + track_design->ride_mode = RIDE_MODE_POWERED_LAUNCH; + if (track_design->vehicle_type == 79) { + if (track_design->ride_mode == 2) + track_design->ride_mode = 1; } } - int unk1 = RCT2_GLOBAL(0x009D8179, uint8); - if (RCT2_GLOBAL(0x009D8178, uint8) == 20) { - unk1 = 0x0097F66C; + rct_object_entry* vehicle_object; + if (track_design->type == RIDE_TYPE_MAZE) { + vehicle_object = RCT2_ADDRESS(0x0097F66C, rct_object_entry); } else { - if (unk1 == 3 && RCT2_GLOBAL(0x009D8178, uint8) == 3) - unk1 = 80; - unk1 = 0x0097F0DC + (unk1 * 16); + int vehicle_type = track_design->vehicle_type; + if (vehicle_type == 3 && track_design->type == RIDE_TYPE_INVERTED_ROLLER_COASTER) + vehicle_type = 80; + vehicle_object = &RCT2_ADDRESS(0x0097F0DC, rct_object_entry)[vehicle_type]; } - memcpy((void*)0x009D81E8, (void*)unk1, 16); + memcpy(&track_design->vehicle_object, vehicle_object, sizeof(rct_object_entry)); for (i = 0; i < 32; i++) - RCT2_ADDRESS(0x009D81FA, uint8)[i] = RCT2_ADDRESS(0x009D8181, uint8)[i * 2]; + track_design->vehicle_additional_colour[i] = track_design->vehicle_colours[i].trim_colour; - RCT2_GLOBAL(0x009D81F8, uint8) = 255; - RCT2_GLOBAL(0x009D81F9, uint8) = 255; - RCT2_GLOBAL(0x009D821A, uint8) = 5; + track_design->space_required_x = 255; + track_design->space_required_y = 255; + track_design->lift_hill_speed_num_circuits = 5; } - RCT2_GLOBAL(0x009D81C8, uint8) = min( - RCT2_GLOBAL(0x009D81C8, uint8), - RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + 5 + (RCT2_GLOBAL(0x009D8178, uint8) * 8), uint8) + track_design->var_50 = min( + track_design->var_50, + RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + 5 + (track_design->type * 8), uint8) ); + return track_design; +} + +/* rct2: 0x006D1DCE*/ +void reset_track_list_cache(){ + int* track_list_cache = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, int); + for (int i = 0; i < 4; ++i){ + track_list_cache[i] = -1; + } + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) = 0; +} + +/* rct2: 0x006D1C68 */ +int backup_map(){ + RCT2_GLOBAL(0xF440ED, uint8*) = malloc(0xED600); + if (RCT2_GLOBAL(0xF440ED, uint32) == 0) return 0; + + RCT2_GLOBAL(0xF440F1, uint8*) = malloc(0x40000); + if (RCT2_GLOBAL(0xF440F1, uint32) == 0){ + free(RCT2_GLOBAL(0xF440ED, uint8*)); + return 0; + } + + RCT2_GLOBAL(0xF440F5, uint8*) = malloc(14); + if (RCT2_GLOBAL(0xF440F5, uint32) == 0){ + free(RCT2_GLOBAL(0xF440ED, uint8*)); + free(RCT2_GLOBAL(0xF440F1, uint8*)); + return 0; + } + + uint32* map_elements = RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS, uint32); + memcpy(RCT2_GLOBAL(0xF440ED, uint32*), map_elements, 0xED600); + + uint32* tile_map_pointers = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, uint32); + memcpy(RCT2_GLOBAL(0xF440F1, uint32*), tile_map_pointers, 0x40000); + + uint8* backup_info = RCT2_GLOBAL(0xF440F5, uint8*); + *(uint32*)backup_info = RCT2_GLOBAL(0x0140E9A4, uint32); + *(uint16*)(backup_info + 4) = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16); + *(uint16*)(backup_info + 6) = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16); + *(uint16*)(backup_info + 8) = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16); + *(uint32*)(backup_info + 10) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); return 1; } +/* rct2: 0x006D2378 */ +void reload_map_backup(){ + uint32* map_elements = RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS, uint32); + memcpy(map_elements, RCT2_GLOBAL(0xF440ED, uint32*), 0xED600); + + uint32* tile_map_pointers = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, uint32); + memcpy(tile_map_pointers, RCT2_GLOBAL(0xF440F1, uint32*), 0x40000); + + uint8* backup_info = RCT2_GLOBAL(0xF440F5, uint8*); + RCT2_GLOBAL(0x0140E9A4, uint32) = *(uint32*)backup_info; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = *(uint16*)(backup_info + 4); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16) = *(uint16*)(backup_info + 6); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) = *(uint16*)(backup_info + 8); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = *(uint32*)(backup_info + 10); + + free(RCT2_GLOBAL(0xF440ED, uint8*)); + free(RCT2_GLOBAL(0xF440F1, uint8*)); + free(RCT2_GLOBAL(0xF440F5, uint8*)); +} + +/* rct2: 0x006D1D9A */ +void blank_map(){ + + // These values were previously allocated in backup map but + // it seems more fitting to place in this function + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = 0x1FE0; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16) = 0x20FE; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) = 0x100; + + rct_map_element* map_element; + for (int i = 0; i < MAX_TILE_MAP_ELEMENT_POINTERS; i++) { + map_element = GET_MAP_ELEMENT(i); + map_element->type = MAP_ELEMENT_TYPE_SURFACE; + map_element->flags = MAP_ELEMENT_FLAG_LAST_TILE; + map_element->base_height = 2; + map_element->clearance_height = 0; + map_element->properties.surface.slope = 0; + map_element->properties.surface.terrain = 0; + map_element->properties.surface.grass_length = 1; + map_element->properties.surface.ownership = OWNERSHIP_OWNED; + } + map_update_tile_pointers(); +} + +/* rct2: 0x006ABDB0 */ +void load_track_scenery_objects(){ + uint8 entry_index = RCT2_GLOBAL(0xF44157, uint8); + rct_object_entry_extended* object_entry = &object_entry_groups[0].entries[entry_index]; + + rct_object_entry* copied_entry = RCT2_ADDRESS(0xF43414, rct_object_entry); + memcpy(copied_entry, object_entry, sizeof(rct_object_entry)); + + object_unload_all(); + object_load(-1, copied_entry, 0); + uint8 entry_type; + find_object_in_entry_group(copied_entry, &entry_type, &entry_index); + RCT2_GLOBAL(0xF44157, uint8) = entry_index; + + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + + if (track_design->type == RIDE_TYPE_MAZE){ + // Skip all of the maze track elements + while (*(uint32*)track_elements != 0)track_elements += sizeof(rct_maze_element); + track_elements += sizeof(rct_maze_element); + } + else{ + // Skip track_elements + while (*track_elements != 255) track_elements += sizeof(rct_track_element); + track_elements++; + + // Skip entrance exit elements + while (*track_elements != 255) track_elements += sizeof(rct_track_entrance); + track_elements++; + } + + while (*track_elements != 255){ + rct_track_scenery* scenery_entry = (rct_track_scenery*)track_elements; + + if (!find_object_in_entry_group(&scenery_entry->scenery_object, &entry_type, &entry_index)){ + object_load(-1, &scenery_entry->scenery_object, 0); + } + // Skip object and location/direction/colour + track_elements += sizeof(rct_track_scenery); + } + + reset_loaded_objects(); +} + +/* rct2: 0x006D247A */ +void track_mirror_scenery(uint8** track_elements){ + rct_track_scenery* scenery = (rct_track_scenery*)*track_elements; + for (; (scenery->scenery_object.flags & 0xFF) != 0xFF; scenery++){ + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(&scenery->scenery_object, &entry_type, &entry_index)){ + entry_type = scenery->scenery_object.flags & 0xF; + if (entry_type != OBJECT_TYPE_PATHS) + continue; + } + + rct_scenery_entry* scenery_entry = (rct_scenery_entry*)object_entry_groups[entry_type].chunks[entry_index]; + + switch (entry_type){ + case OBJECT_TYPE_LARGE_SCENERY: + { + sint16 x1 = 0, x2 = 0, y1 = 0, y2 = 0; + for (rct_large_scenery_tile* tile = scenery_entry->large_scenery.tiles; + tile->x_offset != -1; + tile++) + { + if (x1 > tile->x_offset) + x1 = tile->x_offset; + if (x2 < tile->x_offset) + x2 = tile->x_offset; + if (y1 > tile->y_offset) + y1 = tile->y_offset; + if (y2 > tile->y_offset) + y2 = tile->y_offset; + } + + switch (scenery->flags & 3){ + case 0: + scenery->y = (-(scenery->y * 32 + y1) - y2) / 32; + break; + case 1: + scenery->x = (scenery->x * 32 + y2 + y1) / 32; + scenery->y = (-(scenery->y * 32)) / 32; + scenery->flags ^= (1 << 1); + break; + case 2: + scenery->y = (-(scenery->y * 32 - y2) + y1) / 32; + break; + case 3: + scenery->x = (scenery->x * 32 - y2 - y1) / 32; + scenery->y = (-(scenery->y * 32)) / 32; + scenery->flags ^= (1 << 1); + break; + } + break; + } + case OBJECT_TYPE_SMALL_SCENERY: + scenery->y = -scenery->y; + + if (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9){ + scenery->flags ^= (1 << 0); + if (!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ + scenery->flags ^= (1 << 2); + } + break; + } + if (scenery->flags & (1 << 0)) + scenery->flags ^= (1 << 1); + + scenery->flags ^= (1 << 2); + break; + + case OBJECT_TYPE_WALLS: + scenery->y = -scenery->y; + if (scenery->flags & (1 << 0)) + scenery->flags ^= (1 << 1); + break; + + case OBJECT_TYPE_PATHS: + scenery->y = -scenery->y; + + if (scenery->flags & (1 << 5)){ + scenery->flags ^= (1 << 6); + } + + uint8 flags = scenery->flags; + flags = ((flags& (1 << 3)) >> 2) | ((flags & (1 << 1)) << 2); + scenery->flags &= 0xF5; + scenery->flags |= flags; + } + + } +} + +/* rct2: 0x006D2443 */ +void track_mirror_ride(uint8** track_elements){ + rct_track_element* track = (rct_track_element*)*track_elements; + for (; track->type != 0xFF; track++){ + track->type = RCT2_ADDRESS(0x0099EA1C, uint8)[track->type]; + } + *track_elements = (uint8*)track + 1; + + rct_track_entrance* entrance = (rct_track_entrance*)*track_elements; + for (; entrance->z != -1; entrance++){ + entrance->y = -entrance->y; + if (entrance->direction & 1){ + entrance->direction ^= (1 << 1); + } + } + *track_elements = (uint8*)entrance + 1; +} + +/* rct2: 0x006D25FA */ +void track_mirror_maze(uint8** track_elements){ + rct_maze_element* maze = (rct_maze_element*)*track_elements; + for (; maze->all != 0; maze++){ + maze->y = -maze->y; + + if (maze->type == 0x8 || maze->type == 0x80){ + if (maze->unk_2 & 1){ + maze->unk_2 ^= (1 << 1); + } + continue; + } + + uint16 maze_entry = maze->maze_entry; + uint16 new_entry = 0; + for (uint8 position = bitscanforward(maze_entry); + position != 0xFF; + position = bitscanforward(maze_entry)){ + maze_entry &= ~(1 << position); + new_entry |= (1 << RCT2_ADDRESS(0x00993EDC, uint8)[position]); + } + maze->maze_entry = new_entry; + } + *track_elements = (uint8*)maze + 4; +} + +/* rct2: 0x006D2436 */ +void track_mirror(){ + uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); + + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + + if (track_design->type == RIDE_TYPE_MAZE){ + track_mirror_maze(&track_elements); + } + else{ + track_mirror_ride(&track_elements); + } + + track_mirror_scenery(&track_elements); +} + +void track_update_max_min_coordinates(sint16 x, sint16 y, sint16 z){ + if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + } + + if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + } + + if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + } + + if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + } + + if (z < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; + } + + if (z > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; + } +} + +/* rct2: 0x006D0964 */ +int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int originX, int originY, int originZ){ + RCT2_GLOBAL(0x00F44050, rct_track_scenery*) = scenery_start; + + // mode + RCT2_GLOBAL(0x00F44154, uint8) = 0; + + for (uint8 mode = 0; mode <= 1; mode++){ + if ((scenery_start->scenery_object.flags & 0xFF) != 0xFF) + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 2; + + if (RCT2_GLOBAL(0x00F4414E, uint8) & (1 << 7)) + continue; + + for (rct_track_scenery* scenery = scenery_start; (scenery->scenery_object.flags & 0xFF) != 0xFF; scenery++){ + + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + + rct_xy8 tile = { .x = originX / 32, .y = originY / 32 }; + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + tile.x += scenery->x; + tile.y += scenery->y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + tile.x += scenery->y; + tile.y -= scenery->x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + tile.x -= scenery->x; + tile.y -= scenery->y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + tile.x -= scenery->y; + tile.y += scenery->x; + break; + } + + rct_xy16 mapCoord = { .x = tile.x * 32, .y = tile.y * 32 }; + track_update_max_min_coordinates(mapCoord.x, mapCoord.y, originZ); + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0 && + mode == 0){ + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == tile.x && selectionTile->y == tile.y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = tile.x; + selectionTile->y = tile.y; + selectionTile++; + selectionTile->x = -1; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6 && + mode == 0){ + + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(&scenery->scenery_object, &entry_type, &entry_index)){ + entry_type = scenery->scenery_object.flags & 0xF; + if (entry_type != OBJECT_TYPE_PATHS) + entry_type = 0xFF; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8)&SCREEN_FLAGS_TRACK_DESIGNER) + entry_type = 0xFF; + + entry_index = 0; + for (rct_path_type* path = g_pathTypeEntries[0]; + entry_index < object_entry_group_counts[OBJECT_TYPE_PATHS]; + path = g_pathTypeEntries[entry_index], entry_index++){ + + if (path == (rct_path_type*)-1) + continue; + if (path->flags & (1 << 2)) + continue; + } + + if (entry_index == object_entry_group_counts[OBJECT_TYPE_PATHS]) + entry_type = 0xFF; + } + int z; + switch (entry_type){ + case OBJECT_TYPE_SMALL_SCENERY: + //bl + rotation += scenery->flags; + rotation &= 3; + + //bh + uint8 quadrant = (scenery->flags >> 2) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + quadrant &= 3; + + uint8 bh = rotation | (quadrant << 6) | MAP_ELEMENT_TYPE_SCENERY; + + rct_scenery_entry* small_scenery = g_smallSceneryEntries[entry_index]; + if (!(small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) && + (small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG9)){ + bh = bh; + } + else if (small_scenery->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25)){ + bh &= 0x3F; + } + + z = (scenery->z * 8 + originZ) / 8; + game_do_command( + mapCoord.x, + 0x69 | bh << 8, + mapCoord.y, + (entry_index << 8) | z, + GAME_COMMAND_REMOVE_SCENERY, + 0, + 0); + break; + case OBJECT_TYPE_LARGE_SCENERY: + z = (scenery->z * 8 + originZ) / 8; + game_do_command( + mapCoord.x, + 0x69 | (((rotation + scenery->flags) & 0x3) << 8), + mapCoord.y, + z, + GAME_COMMAND_REMOVE_LARGE_SCENERY, + 0, + 0); + break; + case OBJECT_TYPE_WALLS: + z = (scenery->z * 8 + originZ) / 8; + game_do_command( + mapCoord.x, + 0x69, + mapCoord.y, + (z << 8) | ((rotation + scenery->flags) & 0x3), + GAME_COMMAND_REMOVE_FENCE, + 0, + 0); + break; + case OBJECT_TYPE_PATHS: + z = (scenery->z * 8 + originZ) / 8; + footpath_remove(mapCoord.x, mapCoord.y, z, 0x69); + break; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ + int z = scenery->z * 8 + RCT2_GLOBAL(0x00F440D5, sint16); + if (z < RCT2_GLOBAL(0x00F44129, sint16)){ + RCT2_GLOBAL(0x00F44129, sint16) = z; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 3 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(&scenery->scenery_object, &entry_type, &entry_index)){ + entry_type = scenery->scenery_object.flags & 0xF; + if (entry_type != OBJECT_TYPE_PATHS){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8)&SCREEN_FLAGS_TRACK_DESIGNER){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + } + + entry_index = 0; + for (rct_path_type* path = g_pathTypeEntries[0]; + entry_index < object_entry_group_counts[OBJECT_TYPE_PATHS]; + path = g_pathTypeEntries[entry_index], entry_index++){ + + if (path == (rct_path_type*)-1) + continue; + if (path->flags & (1 << 2)) + continue; + } + + if (entry_index == object_entry_group_counts[OBJECT_TYPE_PATHS]){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + } + } + + money32 cost; + sint16 z; + uint8 bl; + + switch (entry_type){ + case OBJECT_TYPE_SMALL_SCENERY: + if (mode != 0) + continue; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + rotation += scenery->flags; + rotation &= 3; + z = scenery->z * 8 + originZ; + uint8 quadrant = ((scenery->flags >> 2) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8)) & 3; + + bl = 0x81; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0xA9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0xE9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0x80; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 1161; + + cost = game_do_command( + mapCoord.x, + bl | (entry_index << 8), + mapCoord.y, + quadrant | (scenery->primary_colour << 8), + GAME_COMMAND_PLACE_SCENERY, + rotation | (scenery->secondary_colour << 16), + z + ); + + if (cost == MONEY32_UNDEFINED) + cost = 0; + break; + case OBJECT_TYPE_LARGE_SCENERY: + if (mode != 0) + continue; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + rotation += scenery->flags; + rotation &= 3; + + z = scenery->z * 8 + originZ; + + bl = 0x81; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0xA9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0xE9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0x80; + + cost = game_do_command( + mapCoord.x, + bl | (rotation << 8), + mapCoord.y, + scenery->primary_colour | (scenery->secondary_colour << 8), + GAME_COMMAND_PLACE_LARGE_SCENERY, + entry_index, + z + ); + + if (cost == MONEY32_UNDEFINED) + cost = 0; + break; + case OBJECT_TYPE_WALLS: + if (mode != 0) + continue; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + z = scenery->z * 8 + originZ; + rotation += scenery->flags; + rotation &= 3; + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0xA9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 1811; + + cost = game_do_command( + mapCoord.x, + bl | (entry_index << 8), + mapCoord.y, + rotation | (scenery->primary_colour << 8), + GAME_COMMAND_41, + z, + scenery->secondary_colour | ((scenery->flags & 0xFC) << 6) + ); + + if (cost == MONEY32_UNDEFINED) + cost = 0; + break; + case OBJECT_TYPE_PATHS: + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + z = (scenery->z * 8 + originZ) / 8; + + if (mode == 0){ + if (scenery->flags & (1 << 7)){ + //dh + entry_index |= (1 << 7); + } + + uint8 bh = ((scenery->flags & 0xF) << rotation); + bl = bh >> 4; + bh = (bh | bl) & 0xF; + bl = (((scenery->flags >> 5) + rotation) & 3) << 5; + bh |= bl; + + bh |= scenery->flags & 0x90; + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + cost = game_do_command(mapCoord.x, bl | (bh << 8), mapCoord.y, z | (entry_index << 8), GAME_COMMAND_18, 0, 0); + } + else{ + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1) + continue; + + rct_map_element* map_element = map_get_path_element_at(mapCoord.x / 32, mapCoord.y / 32, z); + + if (map_element == NULL) + continue; + + sub_6A7594(); + sub_6A6AA7(mapCoord.x, mapCoord.y, map_element); + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + + sub_6A6C66(mapCoord.x, mapCoord.y, map_element, bl); + sub_6A759F(); + continue; + } + break; + default: + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + break; + } + RCT2_GLOBAL(0x00F440D5, money32) += cost; + if (RCT2_GLOBAL(0x00F440D4, uint8) != 2){ + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = MONEY32_UNDEFINED; + } + } + + if (RCT2_GLOBAL(0x00F440D5, money32) != MONEY32_UNDEFINED) + continue; + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 2) + continue; + + return 0; + } + } + } + return 1; +} + +int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** track_elements) +{ + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + gMapSelectionTiles->x = -1; + RCT2_GLOBAL(0x009DEA48, sint16) = x; + RCT2_GLOBAL(0x009DEA4A, sint16) = y; + + RCT2_GLOBAL(0x009DEA4C, sint16) = map_element_height(x, y) & 0xFFFF; + RCT2_GLOBAL(0x009DEA4E, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + } + + RCT2_GLOBAL(0x00F440D5, uint32) = 0; + + rct_maze_element* maze = (rct_maze_element*)(*track_elements); + for (; maze->all != 0; maze++){ + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + rct_xy16 mapCoord = { .x = maze->x * 32, .y = maze->y * 32 }; + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + break; + case MAP_ELEMENT_DIRECTION_NORTH:{ + int temp_x = -mapCoord.x; + mapCoord.x = mapCoord.y; + mapCoord.y = temp_x; + } + break; + case MAP_ELEMENT_DIRECTION_EAST: + mapCoord.x = -mapCoord.x; + mapCoord.y = -mapCoord.y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH:{ + int temp_y = -mapCoord.y; + mapCoord.y = mapCoord.x; + mapCoord.x = temp_y; + } + break; + } + + mapCoord.x += x; + mapCoord.y += y; + + track_update_max_min_coordinates(mapCoord.x, mapCoord.y, z); + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == mapCoord.x && selectionTile->y == mapCoord.y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = mapCoord.x; + selectionTile->y = mapCoord.y; + selectionTile++; + selectionTile->x = -1; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + + uint8 bl; + money32 cost = 0; + uint16 maze_entry; + + switch (maze->type){ + case 0x08: + // entrance + rotation += maze->unk_2; + rotation &= 3; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0x69; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1){ + cost = game_do_command(mapCoord.x, 0 | rotation << 8, mapCoord.y, (z / 16) & 0xFF, GAME_COMMAND_12, -1, 0); + } + else{ + cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex, GAME_COMMAND_12, 0, 0); + } + if (cost != MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + } + break; + case 0x80: + // exit + rotation += maze->unk_2; + rotation &= 3; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0x69; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1){ + cost = game_do_command(mapCoord.x, 0 | rotation << 8, mapCoord.y, ((z / 16) & 0xFF) | (1 << 8), GAME_COMMAND_12, -1, 0); + } + else{ + cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex | (1 << 8), GAME_COMMAND_12, 0, 0); + } + if (cost != MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + } + break; + default: + maze_entry = rol16(maze->maze_entry, rotation * 4); + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0x29; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0x69; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + + cost = game_do_command(mapCoord.x, bl | (maze_entry & 0xFF) << 8, mapCoord.y, rideIndex | (maze_entry & 0xFF00), GAME_COMMAND_49, z, 0); + break; + } + + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + return 0; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ + if (mapCoord.x > 0x1FFF) + continue; + if (mapCoord.y > 0x1FFF) + continue; + if (mapCoord.x < 0) + continue; + if (mapCoord.y < 0) + continue; + + rct_map_element* map_element = map_get_surface_element_at(mapCoord.x / 32, mapCoord.y / 32); + + sint16 map_height = map_element->base_height * 8; + + if (map_element->properties.surface.slope & 0xF){ + map_height += 16; + if (map_element->properties.surface.slope & 0x10){ + map_height += 16; + } + } + + if (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){ + sint16 water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + water_height *= 16; + if (water_height > map_height) + map_height = water_height; + } + + sint16 temp_z = z + RCT2_GLOBAL(0x00F440D5, sint16) - map_height; + if (temp_z < 0) + RCT2_GLOBAL(0x00F440D5, sint16) -= temp_z; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ + game_do_command(0, 0x69, 0, rideIndex, GAME_COMMAND_7, 0, 0); + } + + RCT2_GLOBAL(0x00F44142, sint16) = x; + RCT2_GLOBAL(0x00F44144, sint16) = y; + RCT2_GLOBAL(0x00F44146, sint16) = z; + + *track_elements = (uint8*)maze + 4; + return 1; +} + +int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** track_elements) +{ + RCT2_GLOBAL(0x00F44142, sint16) = x; + RCT2_GLOBAL(0x00F44144, sint16) = y; + RCT2_GLOBAL(0x00F44146, sint16) = z; + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + gMapSelectionTiles->x = -1; + RCT2_GLOBAL(0x009DEA48, sint16) = x; + RCT2_GLOBAL(0x009DEA4A, sint16) = y; + + RCT2_GLOBAL(0x009DEA4C, sint16) = map_element_height(x, y) & 0xFFFF; + RCT2_GLOBAL(0x009DEA4E, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + } + + RCT2_GLOBAL(0x00F440D5, uint32) = 0; + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + + rct_track_element* track = (rct_track_element*)(*track_elements); + for (; track->type != 0xFF; track++){ + + uint8 track_type = track->type; + if (track_type == TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) + track_type = 0xFF; + + track_update_max_min_coordinates(x, y, z); + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + for (rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; + trackBlock->var_00 != 0xFF; + trackBlock++){ + rct_xy16 tile; + tile.x = x; + tile.y = y; + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + tile.x += trackBlock->x; + tile.y += trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + tile.x += trackBlock->y; + tile.y -= trackBlock->x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + tile.x -= trackBlock->x; + tile.y -= trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + tile.x -= trackBlock->y; + tile.y += trackBlock->x; + break; + } + + track_update_max_min_coordinates(tile.x, tile.y, z); + + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == tile.x && selectionTile->y == tile.y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = tile.x; + selectionTile->y = tile.y; + selectionTile++; + selectionTile->x = -1; + } + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ + const rct_track_coordinates* track_coordinates = &TrackCoordinates[track_type]; + + //di + int temp_z = z; + temp_z -= track_coordinates->z_negative; + rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; + + temp_z += trackBlock->z; + // rotation in bh + // track_type in dl + game_do_command(x, 0x69 | ((rotation & 3) << 8), y, track_type, GAME_COMMAND_4, temp_z, 0); + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + const rct_track_coordinates* track_coordinates = &TrackCoordinates[track_type]; + + //di + int temp_z = z; + temp_z -= track_coordinates->z_negative; + uint32 edi = ((track->flags & 0xF) << 17) | + ((track->flags & 0xF) << 28) | + (((track->flags >> 4) & 0x3) << 24) | + (temp_z & 0xFFFF); + + int edx = RCT2_GLOBAL(0x00F440A7, uint8) | (track_type << 8); + + if (track->flags & 0x80)edx |= 0x10000; + if (track->flags & 0x40)edx |= 0x20000; + + uint8 bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + money32 cost = game_do_command(x, bl | (rotation << 8), y, edx, GAME_COMMAND_3, edi, 0); + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + return 0; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ + for (rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; + trackBlock->var_00 != 0xFF; + trackBlock++){ + rct_xy16 tile; + tile.x = x; + tile.y = y; + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + tile.x += trackBlock->x; + tile.y += trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + tile.x += trackBlock->y; + tile.y -= trackBlock->x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + tile.x -= trackBlock->x; + tile.y -= trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + tile.x -= trackBlock->y; + tile.y += trackBlock->x; + break; + } + + if (tile.x > 0x1FFF) + continue; + + if (tile.y > 0x1FFF) + continue; + + if (tile.x < 0) + continue; + + if (tile.y < 0) + continue; + + rct_map_element* map_element = map_get_surface_element_at(tile.x / 32, tile.y / 32); + + if (map_element == NULL) + return 0; + + int height = map_element->base_height * 8; + if (map_element->properties.surface.slope & 0xF){ + height += 16; + if (map_element->properties.surface.slope & 0x10){ + height += 16; + } + } + + uint8 water_height = 16 * map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + if (water_height){ + if (water_height > height){ + height = water_height; + } + } + int temp_z = z + RCT2_GLOBAL(0x00F440D5, sint16); + temp_z -= height; + + if (temp_z < 0){ + RCT2_GLOBAL(0x00F440D5, sint16) -= temp_z; + } + } + } + + const rct_track_coordinates* track_coordinates = &TrackCoordinates[track_type]; + rotation &= 3; + switch (rotation & 3){ + case 0: + x += track_coordinates->x; + y += track_coordinates->y; + break; + case 1: + x += track_coordinates->y; + y -= track_coordinates->x; + break; + case 2: + x -= track_coordinates->x; + y -= track_coordinates->y; + break; + case 3: + x -= track_coordinates->y; + y += track_coordinates->x; + break; + } + + z -= track_coordinates->z_negative; + z += track_coordinates->z_positive; + + rotation += track_coordinates->rotation_positive - track_coordinates->rotation_negative; + rotation &= 3; + if (track_coordinates->rotation_positive & (1 << 2)) + rotation |= (1 << 2); + + if (!(rotation & (1 << 2))){ + x += RCT2_ADDRESS(0x00993CCC, sint16)[rotation * 2]; + y += RCT2_ADDRESS(0x00993CCE, sint16)[rotation * 2]; + } + } + + // Entrance elements + //0x6D06D8 + *track_elements = (uint8*)track + 1; + rct_track_entrance* entrance = (rct_track_entrance*)(*track_elements); + for (; entrance->z != -1; entrance++){ + rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + x = entrance->x; + y = entrance->y; + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + break; + case MAP_ELEMENT_DIRECTION_NORTH:{ + int temp_x = -x; + x = y; + y = temp_x; + } + break; + case MAP_ELEMENT_DIRECTION_EAST: + x = -x; + y = -y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH:{ + int temp_y = -y; + y = x; + x = temp_y; + } + break; + } + + x += RCT2_GLOBAL(0x00F44142, sint16); + y += RCT2_GLOBAL(0x00F44144, sint16); + + + track_update_max_min_coordinates(x, y, z); + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == x && selectionTile->y == y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = x; + selectionTile->y = y; + selectionTile++; + selectionTile->x = -1; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + + //bh + rotation += entrance->direction; + rotation &= 3; + + //dh rideIndex is dl + uint8 is_exit = 0; + if (entrance->direction & (1 << 7)){ + is_exit = 1; + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) != 1){ + rct_xy16 tile; + tile.x = x + RCT2_ADDRESS(0x00993CCC, sint16)[rotation * 2]; + tile.y = y + RCT2_ADDRESS(0x00993CCE, sint16)[rotation * 2]; + + rct_map_element* map_element = map_get_first_element_at(tile.x / 32, tile.y / 32); + z = RCT2_GLOBAL(0x00F44146, sint16) / 8; + + z += (entrance->z == (sint8)0x80) ? -1 : entrance->z; + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (map_element->base_height != z) + continue; + + int di = (map_element->properties.track.sequence >> 4) & 0x7; + uint8 bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + money32 cost = game_do_command(x, bl | (rotation << 8), y, rideIndex | (is_exit << 8), GAME_COMMAND_12, di, 0); + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + return 0; + } + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + break; + } while (!map_element_is_last_for_tile(map_element++)); + } + else{ + //dl + z = (entrance->z == (sint8)0x80) ? -1 : entrance->z; + z *= 8; + z += RCT2_GLOBAL(0x00F44146, sint16); + z /= 16; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + money32 cost = game_do_command(x, 0 | (rotation << 8), y, z | (is_exit << 8), GAME_COMMAND_12, -1, 0); + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + return 0; + } + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + } + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ + RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, RCT2_GLOBAL(0x00F440A7, uint8), 0, 0, 0); + rct_ride* ride = GET_RIDE(RCT2_GLOBAL(0x00F440A7, uint8)); + user_string_free(ride->name); + ride->type = RIDE_TYPE_NULL; + } + + *track_elements = ((uint8*)(entrance)) + 1; + + return 1; +} + +/** +* Places a virtual track. This can involve highlighting the surface tiles and showing the track layout. It is also used by +* the track preview window to place the whole track. +* Depending on the value of bl it modifies the function. +* bl == 0, Draw outlines on the ground +* bl == 1, +* bl == 2, +* bl == 3, Returns the z value of a succesful placement. Only lower 16 bits are the value, the rest may be garbage? +* bl == 4, +* bl == 5, Returns cost to create the track. All 32 bits are used. Places the track. (used by the preview) +* bl == 6, Clear white outlined track. +* rct2: 0x006D01B3 +*/ +int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) +{ + RCT2_GLOBAL(0x00F4414E, uint8) = bl & 0x80; + RCT2_GLOBAL(0x00F440D4, uint8) = bl & 0x7F; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) != 0){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 0x80; + } + RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; + + RCT2_GLOBAL(0x00F44129, uint16) = 0; + uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); + + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + uint8 track_place_success = 0; + + if (track_design->type == RIDE_TYPE_MAZE){ + track_place_success = track_place_maze(x, y, z, rideIndex, &track_elements); + } + else{ + track_place_success = track_place_ride(x, y, z, rideIndex, &track_elements); + } + // Scenery elements + rct_track_scenery* scenery = (rct_track_scenery*)track_elements; + + if (track_place_success){ + if (!track_place_scenery( + scenery, + rideIndex, + RCT2_GLOBAL(0x00F44142, sint16), + RCT2_GLOBAL(0x00F44144, sint16), + RCT2_GLOBAL(0x00F44146, sint16))){ + return RCT2_GLOBAL(0x00F440D5, money32); + } + } + + //0x6D0FE6 + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 0x6; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 3); + map_invalidate_map_selection_tiles(); + } + + if (bl == 3) + return RCT2_GLOBAL(0x00F440D5, sint16); + return RCT2_GLOBAL(0x00F440D5, money32); + + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = bl; + ecx = y; + edx = z; + esi = 0; + edi = 0; + ebp = 0; + RCT2_CALLFUNC_X(0x006D01B3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + if (bl == 3) + ebx &= 0xFFFF; + return ebx; +} + +/* rct2: 0x006D2189 + * ebx = ride_id + * cost = edi + */ +int sub_6D2189(int* cost, uint8* ride_id){ + RCT2_GLOBAL(0xF44151, uint8) = 0; + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + uint8 entry_type, entry_index; + + if (!find_object_in_entry_group(&track_design->vehicle_object, &entry_type, &entry_index)) + entry_index = 0xFF; + + int eax = 0, ebx, ecx = 0, edx, esi, edi = 0, ebp = 0; + ebx = 41; + edx = track_design->type | (entry_index << 8); + esi = GAME_COMMAND_6; + + if (MONEY32_UNDEFINED == game_do_command_p(GAME_COMMAND_6, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp)) return 1; + + // bh + *ride_id = edi & 0xFF; + + rct_ride* ride = GET_RIDE(*ride_id); + + uint8* ride_name = RCT2_ADDRESS(0x9E3504, uint8); + rct_string_id new_ride_name = user_string_allocate(132, ride_name); + + if (new_ride_name){ + rct_string_id old_name = ride->name; + ride->name = new_ride_name; + user_string_free(old_name); + } + + uint8 version = track_design->version_and_colour_scheme >> 2; + + if (version == 2){ + ride->entrance_style = track_design->entrance_style; + } + + if (version != 0){ + memcpy(&ride->track_colour_main, &track_design->track_spine_colour, 4); + memcpy(&ride->track_colour_additional, &track_design->track_rail_colour, 4); + memcpy(&ride->track_colour_supports, &track_design->track_support_colour, 4); + } + else{ + memset(&ride->track_colour_main, track_design->track_spine_colour_rct1, 4); + memset(&ride->track_colour_additional, track_design->track_rail_colour_rct1, 4); + memset(&ride->track_colour_supports, track_design->track_support_colour_rct1, 4); + } + + RCT2_GLOBAL(0x009D8150, uint8) |= 1; + uint8 backup_rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + uint32 backup_park_flags = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; + int map_size = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) << 4; + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = 0; + int z = sub_6D01B3(3, 0, map_size, map_size, 16); + + if (RCT2_GLOBAL(0xF4414E, uint8) & 4){ + RCT2_GLOBAL(0xF44151, uint8) |= 2; + } + //dx + z += 16 - RCT2_GLOBAL(0xF44129, uint16); + + int bl = 5; + if (RCT2_GLOBAL(0xF4414E, uint8) & 2){ + bl |= 0x80; + RCT2_GLOBAL(0xF44151, uint8) |= 1; + } + edi = sub_6D01B3(bl, *ride_id, map_size, map_size, z); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = backup_park_flags; + + if (edi != MONEY32_UNDEFINED){ + + if (!find_object_in_entry_group(&track_design->vehicle_object, &entry_type, &entry_index)){ + RCT2_GLOBAL(0xF44151, uint8) |= 4; + } + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = backup_rotation; + RCT2_GLOBAL(0x009D8150, uint8) &= ~1; + *cost = edi; + return 1; + } + else{ + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = backup_rotation; + user_string_free(ride->name); + ride->type = RIDE_TYPE_NULL; + RCT2_GLOBAL(0x009D8150, uint8) &= ~1; + return 0; + } +} + +/* rct2: 0x006D235B */ +void sub_6D235B(uint8 ride_id){ + rct_ride* ride = GET_RIDE(ride_id); + user_string_free(ride->name); + ride->type = RIDE_TYPE_NULL; +} + +/* rct2: 0x006D1EF0 */ +void draw_track_preview(uint8** preview){ + // Make a copy of the map + if (!backup_map())return; + + blank_map(); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER){ + load_track_scenery_objects(); + } + + int cost; + uint8 ride_id; + + if (!sub_6D2189(&cost, &ride_id)){ + memset(preview, 0, TRACK_PREVIEW_IMAGE_SIZE * 4); + reload_map_backup(); + return; + } + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_COST, money32) = cost; + + rct_viewport* view = RCT2_ADDRESS(0x9D8161, rct_viewport); + rct_drawpixelinfo* dpi = RCT2_ADDRESS(0x9D8151, rct_drawpixelinfo); + int left, top, right, bottom; + + int center_x = (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)) / 2 + 16; + int center_y = (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)) / 2 + 16; + int center_z = (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16)) / 2; + + int width = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16); + int height = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16); + + if (width < height) + width = height; + + int zoom_level = 1; + + if (width > 1120) + zoom_level = 2; + + if (width > 2240) + zoom_level = 3; + + width = 370 << zoom_level; + height = 217 << zoom_level; + + int x = center_y - center_x - width / 2; + int y = (center_y + center_x) / 2 - center_z - height / 2; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = 0; + + view->width = 370; + view->height = 217; + view->view_width = width; + view->view_height = height; + view->x = 0; + view->y = 0; + view->view_x = x; + view->view_y = y; + view->zoom = zoom_level; + view->flags = VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_INVISIBLE_SPRITES; + + dpi->zoom_level = zoom_level; + dpi->x = 0; + dpi->y = 0; + dpi->width = 370; + dpi->height = 217; + dpi->pitch = 0; + dpi->bits = (char*)preview; + + top = y; + left = x; + bottom = y + height; + right = x + width; + + viewport_paint(view, dpi, left, top, right, bottom); + + dpi->bits += TRACK_PREVIEW_IMAGE_SIZE; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = 1; + x = -center_y - center_x - width / 2; + y = (center_y - center_x) / 2 - center_z - height / 2; + + view->view_x = x; + view->view_y = y; + top = y; + left = x; + bottom = y + height; + right = x + width; + + viewport_paint(view, dpi, left, top, right, bottom); + + dpi->bits += TRACK_PREVIEW_IMAGE_SIZE; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = 2; + x = center_x - center_y - width / 2; + y = (-center_y - center_x) / 2 - center_z - height / 2; + + view->view_x = x; + view->view_y = y; + top = y; + left = x; + bottom = y + height; + right = x + width; + + viewport_paint(view, dpi, left, top, right, bottom); + + dpi->bits += TRACK_PREVIEW_IMAGE_SIZE; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = 3; + x = center_x + center_y - width / 2; + y = (center_x - center_y) / 2 - center_z - height / 2; + + view->view_x = x; + view->view_y = y; + top = y; + left = x; + bottom = y + height; + right = x + width; + + viewport_paint(view, dpi, left, top, right, bottom); + + sub_6D235B(ride_id); + reload_map_backup(); +} + /** * * I don't think preview is a necessary output argument. It can be obtained easily using the track design structure. @@ -382,45 +2179,1252 @@ int sub_67726A(const char *path) rct_track_design *track_get_info(int index, uint8** preview) { rct_track_design *trackDesign; - uint8 *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); int i; trackDesign = NULL; // Check if track design has already been loaded for (i = 0; i < 4; i++) { - if (index == RCT2_ADDRESS(0x00F44109, uint32)[i]) { - trackDesign = &RCT2_GLOBAL(0x00F44105, rct_track_design*)[i]; + if (index == RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i]) { + trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; break; } } if (trackDesign == NULL) { // Load track design - i = RCT2_GLOBAL(0x00F44119, uint32); - RCT2_GLOBAL(0x00F44119, uint32)++; - if (RCT2_GLOBAL(0x00F44119, uint32) >= 4) - RCT2_GLOBAL(0x00F44119, uint32) = 0; + i = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32)++; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) >= 4) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) = 0; - RCT2_ADDRESS(0x00F44109, uint32)[i] = index; - subsitute_path((char*)0x0141EF68, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignList + (index * 128)); - if (!sub_67726A((char*)0x0141EF68)) { + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = index; + + char track_path[MAX_PATH] = { 0 }; + subsitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignList + (index * 128)); + + rct_track_td6* loaded_track = NULL; + + log_verbose("Loading track: %s", trackDesignList + (index * 128)); + + if (!(loaded_track = load_track_design(track_path))) { if (preview != NULL) *preview = NULL; + // Mark cache as empty. + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = 0; + log_error("Failed to load track: %s", trackDesignList + (index * 128)); return NULL; } - trackDesign = &RCT2_GLOBAL(0x00F44105, rct_track_design*)[i]; + trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; - memcpy(trackDesign, (void*)0x009D8178, 163); - RCT2_CALLPROC_EBPSAFE(0x006D1EF0); + // Copy the track design apart from the preview image + memcpy(&trackDesign->track_td6, loaded_track, sizeof(rct_track_td6)); + // Load in a new preview image, calculate cost variable, calculate var_06 + draw_track_preview((uint8**)trackDesign->preview); + //RCT2_CALLPROC_X(0x006D1EF0, 0, 0, 0, 0, 0, (int)&trackDesign->preview, 0); - trackDesign->cost = RCT2_GLOBAL(0x00F4411D, money32); - trackDesign->var_06 = RCT2_GLOBAL(0x00F44151, uint8) & 7; + trackDesign->track_td6.cost = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_COST, money32); + trackDesign->track_td6.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; } // Set preview to correct preview image based on rotation if (preview != NULL) - *preview = trackDesign->preview[RCT2_GLOBAL(0x00F440AE, uint8)]; + *preview = trackDesign->preview[RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8)]; return trackDesign; -} \ No newline at end of file +} + +/** + * + * rct2: 0x006D3664 + */ +int track_rename(const char *text) +{ + const char* txt_chr = text; + + while (*txt_chr != '\0'){ + switch (*txt_chr){ + case '.': + case '/': + case '\\': + case '*': + case '?': + // Invalid characters + RCT2_GLOBAL(0x141E9AC, uint16) = 3353; + return 0; + } + txt_chr++; + } + + char new_path[MAX_PATH]; + subsitute_path(new_path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), text); + strcat(new_path, ".TD6"); + + rct_window* w = window_find_by_class(WC_TRACK_DESIGN_LIST); + + char old_path[MAX_PATH]; + subsitute_path(old_path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, char)[128 * w->track_list.var_482]); + + if (!platform_file_move(old_path, new_path)) { + RCT2_GLOBAL(0x141E9AC, uint16) = 3354; + return 0; + } + + ride_list_item item = { 0xFC, 0 }; + track_load_list(item); + + item.type = RCT2_GLOBAL(0xF44158, uint8); + item.entry_index = RCT2_GLOBAL(0xF44159, uint8); + track_load_list(item); + + reset_track_list_cache(); + + window_invalidate(w); + return 1; +} + +/** + * + * rct2: 0x006D3761 + */ +int track_delete() +{ + rct_window* w = window_find_by_class(WC_TRACK_DESIGN_LIST); + + char path[MAX_PATH]; + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, char)[128 * w->track_list.var_482]); + + if (!platform_file_delete(path)) { + RCT2_GLOBAL(0x141E9AC, uint16) = 3355; + return 0; + } + + ride_list_item item = { 0xFC, 0 }; + track_load_list(item); + + item.type = RCT2_GLOBAL(0xF44158, uint8); + item.entry_index = RCT2_GLOBAL(0xF44159, uint8); + track_load_list(item); + + reset_track_list_cache(); + + window_invalidate(w); + return 1; +} + +/** + * Helper method to determine if a connects to b by its bank and angle, not location. + */ +int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b) +{ + int trackType, aBank, aAngle, bBank, bAngle; + rct_ride *ride; + + ride = GET_RIDE(a->properties.track.ride_index); + trackType = a->properties.track.type; + aBank = gTrackDefinitions[trackType].bank_end; + aAngle = gTrackDefinitions[trackType].vangle_end; + if (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 8) { + if (a->properties.track.colour & 4) { + if (aBank == TRACK_BANK_NONE) + aBank = TRACK_BANK_UPSIDE_DOWN; + else if (aBank == TRACK_BANK_UPSIDE_DOWN) + aBank = TRACK_BANK_NONE; + } + } + + ride = GET_RIDE(b->properties.track.ride_index); + trackType = b->properties.track.type; + bBank = gTrackDefinitions[trackType].bank_start; + bAngle = gTrackDefinitions[trackType].vangle_start; + if (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 8) { + if (b->properties.track.colour & 4) { + if (bBank == TRACK_BANK_NONE) + bBank = TRACK_BANK_UPSIDE_DOWN; + else if (bBank == TRACK_BANK_UPSIDE_DOWN) + bBank = TRACK_BANK_NONE; + } + } + + return aBank == bBank && aAngle == bAngle; +} + +/* Based on rct2: 0x006D2897 */ +int copy_scenery_to_track(uint8** track_pointer){ + rct_track_scenery* track_scenery = (rct_track_scenery*)(*track_pointer - 1); + rct_track_scenery* scenery_source = RCT2_ADDRESS(0x009DA193, rct_track_scenery); + + while (1){ + int ebx = 0; + memcpy(track_scenery, scenery_source, sizeof(rct_track_scenery)); + if ((track_scenery->scenery_object.flags & 0xFF) == 0xFF) break; + + //0x00F4414D is direction of track? + if ((track_scenery->scenery_object.flags & 0xF) == OBJECT_TYPE_PATHS){ + + uint8 slope = (track_scenery->flags & 0x60) >> 5; + slope -= RCT2_GLOBAL(0x00F4414D, uint8); + + track_scenery->flags &= 0x9F; + track_scenery->flags |= ((slope & 3) << 5); + + // Direction of connection on path + uint8 direction = track_scenery->flags & 0xF; + // Rotate the direction by the track direction + direction = ((direction << 4) >> RCT2_GLOBAL(0x00F4414D, uint8)); + + track_scenery->flags &= 0xF0; + track_scenery->flags |= (direction & 0xF) | (direction >> 4); + + } + else if ((track_scenery->scenery_object.flags & 0xF) == OBJECT_TYPE_WALLS){ + uint8 direction = track_scenery->flags & 3; + + direction -= RCT2_GLOBAL(0x00F4414D, uint8); + + track_scenery->flags &= 0xFC; + track_scenery->flags |= (direction & 3); + } + else { + uint8 direction = track_scenery->flags & 3; + uint8 quadrant = (track_scenery->flags & 0xC) >> 2; + + direction -= RCT2_GLOBAL(0x00F4414D, uint8); + quadrant -= RCT2_GLOBAL(0x00F4414D, uint8); + + track_scenery->flags &= 0xF0; + track_scenery->flags |= (direction & 3) | ((quadrant & 3) << 2); + } + int x = ((uint8)track_scenery->x) * 32 - RCT2_GLOBAL(0x00F44142, sint16); + int y = ((uint8)track_scenery->y) * 32 - RCT2_GLOBAL(0x00F44144, sint16); + + switch (RCT2_GLOBAL(0x00F4414D, uint8)){ + case 0: + break; + case 1: + { + int temp_y = y; + y = x; + x = -temp_y; + } + break; + case 2: + x = -x; + y = -y; + break; + case 3: + { + int temp_x = x; + x = y; + y = -temp_x; + } + break; + } + + x /= 32; + y /= 32; + + if (x > 127 || y > 127 || x < -126 || y < -126){ + window_error_open(3346, 3347); + return 0; + } + + track_scenery->x = x; + track_scenery->y = y; + + int z = track_scenery->z * 8 - RCT2_GLOBAL(0xF44146, sint16); + + z /= 8; + + if (z > 127 || z < -126){ + window_error_open(3346, 3347); + return 0; + } + + track_scenery->z = z; + + track_scenery++; + scenery_source++; + } + + *track_pointer = (uint8*)track_scenery; + //Skip end of scenery elements byte + (*track_pointer)++; + return 1; +} + +/* rct2: 0x006CEAAE */ +int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_elements){ + rct_map_element* map_element; + uint8 map_found = 0; + + sint16 start_x, start_y; + + for (start_y = 0; start_y < 8192; start_y += 32){ + for (start_x = 0; start_x < 8192; start_x += 32){ + map_element = map_get_first_element_at(start_x / 32, start_y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (map_element->properties.track.ride_index == rideIndex){ + map_found = 1; + break; + } + } while (!map_element_is_last_for_tile(map_element++)); + + if (map_found) + break; + } + if (map_found) + break; + } + + if (map_found == 0){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + RCT2_GLOBAL(0x00F44142, sint16) = start_x; + RCT2_GLOBAL(0x00F44144, sint16) = start_y; + RCT2_GLOBAL(0x00F44146, sint16) = map_element->base_height * 8; + + rct_maze_element* maze = (rct_maze_element*)track_elements; + + // x is defined here as we can start the search + // on tile start_x, start_y but then the next row + // must restart on 0 + for (sint16 y = start_y, x = start_x; y < 8192; y += 32){ + for (; x < 8192; x += 32){ + map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (map_element->properties.track.ride_index != rideIndex) + continue; + + maze->maze_entry = map_element->properties.track.maze_entry; + maze->x = (x - start_x) / 32; + maze->y = (y - start_y) / 32; + maze++; + + if (maze >= RCT2_ADDRESS(0x009DA151, rct_maze_element)){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + } while (!map_element_is_last_for_tile(map_element++)); + + } + x = 0; + } + + rct_ride* ride = GET_RIDE(rideIndex); + uint16 location = ride->entrances[0]; + + if (location == 0xFFFF){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + sint16 x = (location & 0xFF) * 32; + sint16 y = ((location & 0xFF00) >> 8) * 32; + + map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (map_element->properties.entrance.type != ENTRANCE_TYPE_RIDE_ENTRANCE) + continue; + if (map_element->properties.entrance.ride_index == rideIndex) + break; + } while (!map_element_is_last_for_tile(map_element++)); + // Add something that stops this from walking off the end + + uint8 entrance_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + maze->unk_2 = entrance_direction; + maze->type = 8; + + maze->x = (sint8)((x - start_x) / 32); + maze->y = (sint8)((y - start_y) / 32); + + maze++; + + location = ride->exits[0]; + + if (location == 0xFFFF){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + x = (location & 0xFF) * 32; + y = ((location & 0xFF00) >> 8) * 32; + + map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (map_element->properties.entrance.type != ENTRANCE_TYPE_RIDE_EXIT) + continue; + if (map_element->properties.entrance.ride_index == rideIndex) + break; + } while (!map_element_is_last_for_tile(map_element++)); + // Add something that stops this from walking off the end + + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + maze->unk_2 = exit_direction; + maze->type = 0x80; + + maze->x = (sint8)((x - start_x) / 32); + maze->y = (sint8)((y - start_y) / 32); + + maze++; + + maze->all = 0; + maze++; + + track_elements = (uint8*)maze; + *track_elements++ = 0xFF; + + RCT2_GLOBAL(0x00F44058, uint8*) = track_elements; + + // Previously you had to save start_x, y, z but + // no need since global vars not used + sub_6D01B3(0, 0, 4096, 4096, 0); + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, sint16) &= 0xFFF9; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, sint16) &= 0xFFF7; + + x = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16); + + y = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16); + + x /= 32; + y /= 32; + x++; + y++; + + track_design->space_required_x = (uint8)x; + track_design->space_required_y = (uint8)y; + + return 1; +} + +/* rct2: 0x006CE68D */ +int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_elements){ + rct_ride* ride = GET_RIDE(rideIndex); + + rct_xy_element trackElement; + + if (sub_6CAF80(rideIndex, &trackElement) == 0){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + int z = 0; + //6ce69e + if (!(sub_6C6402(&trackElement.element, &trackElement.x, &trackElement.y, &z))){ + rct_map_element* initial_map = trackElement.element; + do { + int x = trackElement.x; + int y = trackElement.y; + rct_map_element* map_element = trackElement.element; + if (sub_6C6402(&map_element, &x, &y, &z)){ + break; + } + trackElement.x = x; + trackElement.y = y; + trackElement.element = map_element; + } while (initial_map != trackElement.element); + } + + z = trackElement.element->base_height * 8; + uint8 track_type = trackElement.element->properties.track.type; + uint8 direction = trackElement.element->type & MAP_ELEMENT_DIRECTION_MASK; + RCT2_GLOBAL(0x00F4414D, uint8) = direction; + + if (sub_6C683D(&trackElement.x, &trackElement.y, &z, direction, track_type, 0, &trackElement.element, 0)){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + const rct_track_coordinates *trackCoordinates = &TrackCoordinates[trackElement.element->properties.track.type]; + // Used in the following loop to know when we have + // completed all of the elements and are back at the + // start. + rct_map_element* initial_map = trackElement.element; + + sint16 start_x = trackElement.x; + sint16 start_y = trackElement.y; + sint16 start_z = z + trackCoordinates->z_negative; + RCT2_GLOBAL(0x00F44142, sint16) = start_x; + RCT2_GLOBAL(0x00F44144, sint16) = start_y; + RCT2_GLOBAL(0x00F44146, sint16) = start_z; + + rct_track_element* track = (rct_track_element*)track_elements; + do{ + track->type = trackElement.element->properties.track.type; + if (track->type == 0xFF) + track->type = 101; + + if (track->type == TRACK_ELEM_LEFT_VERTICAL_LOOP || + track->type == TRACK_ELEM_RIGHT_VERTICAL_LOOP) + track_design->flags |= (1 << 7); + + if (track->type == TRACK_ELEM_LEFT_TWIST_DOWN_TO_UP || + track->type == TRACK_ELEM_RIGHT_TWIST_DOWN_TO_UP || + track->type == TRACK_ELEM_LEFT_TWIST_UP_TO_DOWN || + track->type == TRACK_ELEM_RIGHT_TWIST_UP_TO_DOWN) + track_design->flags |= (1 << 17); + + if (track->type == TRACK_ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN || + track->type == TRACK_ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN || + track->type == TRACK_ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP || + track->type == TRACK_ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP) + track_design->flags |= (1 << 29); + + if (track->type == TRACK_ELEM_HALF_LOOP_UP || + track->type == TRACK_ELEM_HALF_LOOP_DOWN) + track_design->flags |= (1 << 18); + + if (track->type == TRACK_ELEM_LEFT_CORKSCREW_UP || + track->type == TRACK_ELEM_RIGHT_CORKSCREW_UP || + track->type == TRACK_ELEM_LEFT_CORKSCREW_DOWN || + track->type == TRACK_ELEM_RIGHT_CORKSCREW_DOWN) + track_design->flags |= (1 << 19); + + if (track->type == TRACK_ELEM_WATER_SPLASH) + track_design->flags |= (1 << 27); + + if (track->type == TRACK_ELEM_POWERED_LIFT) + track_design->flags |= (1 << 30); + + if (track->type == TRACK_ELEM_LEFT_LARGE_HALF_LOOP_UP || + track->type == TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_UP || + track->type == TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_DOWN || + track->type == TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN) + track_design->flags |= (1 << 31); + + if (track->type == TRACK_ELEM_LOG_FLUME_REVERSER) + track_design->var_6C |= (1 << 1); + + uint8 bh; + if (track->type == TRACK_ELEM_BRAKES){ + bh = trackElement.element->properties.track.sequence >> 4; + } + else{ + bh = trackElement.element->properties.track.colour >> 4; + } + + uint8 flags = trackElement.element->type & (1 << 7) | bh; + flags |= (trackElement.element->properties.track.colour & 3) << 4; + + if (RCT2_ADDRESS(0x0097D4F2, uint16)[ride->type * 4] & (1 << 3) && + trackElement.element->properties.track.colour & (1 << 2)){ + flags |= (1 << 6); + } + + track->flags = flags; + track++; + + if (!track_get_next(&trackElement, &trackElement)) + break; + + z = trackElement.element->base_height * 8; + direction = trackElement.element->type & MAP_ELEMENT_DIRECTION_MASK; + track_type = trackElement.element->properties.track.type; + + if (sub_6C683D(&trackElement.x, &trackElement.y, &z, direction, track_type, 0, &trackElement.element, 0)) + break; + + } while (trackElement.element != initial_map); + + track_elements = (uint8*)track; + // Mark the elements as finished. + *track_elements++ = 0xFF; + + rct_track_entrance* entrance = (rct_track_entrance*)track_elements; + + // First entrances, second exits + for (int i = 0; i < 2; ++i){ + + for (int station_index = 0; station_index < 4; ++station_index){ + + z = ride->station_heights[station_index]; + + uint16 location; + if (i == 0)location = ride->entrances[station_index]; + else location = ride->exits[station_index]; + + if (location == 0xFFFF) + continue; + + int x = (location & 0xFF) * 32; + int y = ((location & 0xFF00) >> 8) * 32; + + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (map_element->base_height == z) + break; + } while (!map_element_is_last_for_tile(map_element++)); + // Add something that stops this from walking off the end + + uint8 entrance_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + entrance_direction -= RCT2_GLOBAL(0x00F4414D, uint8); + entrance_direction &= MAP_ELEMENT_DIRECTION_MASK; + + entrance->direction = entrance_direction; + + x -= RCT2_GLOBAL(0x00F44142, sint16); + y -= RCT2_GLOBAL(0x00F44144, sint16); + + switch (RCT2_GLOBAL(0x00F4414D, uint8)){ + case MAP_ELEMENT_DIRECTION_WEST: + // Nothing required + break; + case MAP_ELEMENT_DIRECTION_NORTH: + { + int temp_y = -y; + y = x; + x = temp_y; + } + break; + case MAP_ELEMENT_DIRECTION_EAST: + x = -x; + y = -y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + { + int temp_x = -x; + x = y; + y = temp_x; + } + break; + } + + entrance->x = x; + entrance->y = y; + + z *= 8; + z -= RCT2_GLOBAL(0x00F44146, sint16); + z /= 8; + + if (z > 127 || z < -126){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + if (z == 0xFF) + z = 0x80; + + entrance->z = z; + + // If this is the exit version + if (i == 1){ + entrance->direction |= (1 << 7); + } + entrance++; + } + } + + track_elements = (uint8*)entrance; + *track_elements++ = 0xFF; + *track_elements++ = 0xFF; + + RCT2_GLOBAL(0x00F44058, uint8*) = track_elements; + + sub_6D01B3(0, 0, 4096, 4096, 0); + + // Resave global vars for scenery reasons. + RCT2_GLOBAL(0x00F44142, sint16) = start_x; + RCT2_GLOBAL(0x00F44144, sint16) = start_y; + RCT2_GLOBAL(0x00F44146, sint16) = start_z; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, sint16) &= 0xFFF9; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, sint16) &= 0xFFF7; + + int x = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16); + + int y = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16); + + x /= 32; + y /= 32; + x++; + y++; + + track_design->space_required_x = x; + track_design->space_required_y = y; + + return 1; +} + +/* rct2: 0x006CE44F */ +int ride_to_td6(uint8 rideIndex){ + rct_ride* ride = GET_RIDE(rideIndex); + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + + track_design->type = ride->type; + rct_object_entry_extended* object = &object_entry_groups[OBJECT_TYPE_RIDE].entries[ride->subtype]; + + // Note we are only copying rct_object_entry in size and + // not the extended as we don't need the chunk size. + memcpy(&track_design->vehicle_object, object, sizeof(rct_object_entry)); + + track_design->ride_mode = ride->mode; + + track_design->version_and_colour_scheme = + (ride->colour_scheme_type & 3) | + (1 << 3); // Version .TD6 + + for (int i = 0; i < 32; ++i){ + track_design->vehicle_colours[i] = ride->vehicle_colours[i]; + track_design->vehicle_additional_colour[i] = ride->vehicle_colours_extended[i]; + } + + for (int i = 0; i < 4; ++i){ + track_design->track_spine_colour[i] = ride->track_colour_main[i]; + track_design->track_rail_colour[i] = ride->track_colour_additional[i]; + track_design->track_support_colour[i] = ride->track_colour_supports[i]; + } + + track_design->depart_flags = ride->depart_flags; + track_design->number_of_trains = ride->num_vehicles; + track_design->number_of_cars_per_train = ride->num_cars_per_train; + track_design->min_waiting_time = ride->min_waiting_time; + track_design->max_waiting_time = ride->max_waiting_time; + track_design->var_50 = ride->operation_option; + track_design->lift_hill_speed_num_circuits = + ride->lift_hill_speed | + (ride->num_circuits << 5); + + track_design->entrance_style = ride->entrance_style; + track_design->max_speed = (sint8)(ride->max_speed / 65536); + track_design->average_speed = (sint8)(ride->average_speed / 65536); + track_design->ride_length = ride_get_total_length(ride) / 65536; + track_design->max_positive_vertical_g = ride->max_positive_vertical_g / 32; + track_design->max_negative_vertical_g = ride->max_negative_vertical_g / 32; + track_design->max_lateral_g = ride->max_lateral_g / 32; + track_design->inversions = ride->inversions; + track_design->drops = ride->drops; + track_design->highest_drop_height = ride->highest_drop_height; + + uint16 total_air_time = (ride->total_air_time * 123) / 1024; + if (total_air_time > 255) + total_air_time = 0; + track_design->total_air_time = (uint8)total_air_time; + + track_design->excitement = ride->ratings.excitement / 10; + track_design->intensity = ride->ratings.intensity / 10; + track_design->nausea = ride->ratings.nausea / 10; + + track_design->upkeep_cost = ride->upkeep_cost; + track_design->flags = 0; + track_design->var_6C = 0; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) + track_design->var_6C |= (1 << 31); + + uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + memset(track_elements, 0, 8000); + + if (track_design->type == RIDE_TYPE_MAZE){ + return maze_ride_to_td6(rideIndex, track_design, track_elements); + } + + return tracked_ride_to_td6(rideIndex, track_design, track_elements); +} + +/* rct2: 0x006771DC but not really its branched from that + * quite far. + */ +int save_track_to_file(rct_track_td6* track_design, char* path){ + window_close_construction_windows(); + + uint8* track_file = malloc(0x8000); + + int length = sawyercoding_encode_td6((char*)track_design, track_file, 0x609F); + + FILE *file; + + log_verbose("saving track %s", path); + file = fopen(path, "wb"); + if (file == NULL) { + free(track_file); + log_error("Failed to save %s", path); + return 0; + } + + fwrite(track_file, length, 1, file); + fclose(file); + free(track_file); + + return 1; +} + +/* rct2: 0x006D2804 & 0x006D264D */ +int save_track_design(uint8 rideIndex){ + rct_ride* ride = GET_RIDE(rideIndex); + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)){ + window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); + return 0; + } + + if (ride->ratings.excitement == 0xFFFF){ + window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); + return 0; + } + + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) { + window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); + return 0; + } + + if (!ride_to_td6(rideIndex)){ + window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); + return 0; + } + + uint8* track_pointer = RCT2_GLOBAL(0x00F44058, uint8*); + if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1){ + if (!copy_scenery_to_track(&track_pointer)) + return 0; + } + + while (track_pointer < RCT2_ADDRESS(0x009DE217, uint8))*track_pointer++ = 0; + + char track_name[MAX_PATH]; + // Get track name + format_string(track_name, ride->name, &ride->name_arguments); + + char path[MAX_PATH]; + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), track_name); + + strcat(path, ".TD6"); + + // Save track design + format_string(RCT2_ADDRESS(0x141ED68, char), 2306, NULL); + + // Track design files + format_string(RCT2_ADDRESS(0x141EE68, char), 2305, NULL); + + pause_sounds(); + + int result = platform_open_common_file_dialog( + 0, + RCT2_ADDRESS(0x141ED68, char), + path, + "*.TD?", + RCT2_ADDRESS(0x141EE68, char)); + + unpause_sounds(); + + if (result == 0){ + ride_list_item item = { .type = 0xFD, .entry_index = 0 }; + track_load_list(item); + return 1; + } + + save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path); + + ride_list_item item = { .type = 0xFC, .entry_index = 0 }; + track_load_list(item); + gfx_invalidate_screen(); + return 1; +} + +/** +* +* rct2: 0x006D399D +*/ +rct_track_design *temp_track_get_info(char* path, uint8** preview) +{ + rct_track_design *trackDesign; + uint8 *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); + int i; + + trackDesign = NULL; + + // Check if track design has already been loaded + for (i = 0; i < 4; i++) { + if (RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] == 0) { + trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; + break; + } + } + + if (trackDesign == NULL) { + // Load track design + i = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32)++; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) >= 4) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) = 0; + + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = 0; + + rct_track_td6* loaded_track = NULL; + + log_verbose("Loading track: %s", path); + + if (!(loaded_track = load_track_design(path))) { + if (preview != NULL) *preview = NULL; + log_error("Failed to load track: %s", path); + return NULL; + } + + trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; + + object_unload_all(); + if (loaded_track->type == RIDE_TYPE_NULL){ + if (preview != NULL) *preview = NULL; + log_error("Failed to load track (ride type null): %s", path); + return NULL; + } + + if (!object_load(0, &loaded_track->vehicle_object, NULL)){ + if (preview != NULL) *preview = NULL; + log_error("Failed to load track (vehicle load fail): %s", path); + return NULL; + } + + // Copy the track design apart from the preview image + memcpy(&trackDesign->track_td6, loaded_track, sizeof(rct_track_td6)); + // Load in a new preview image, calculate cost variable, calculate var_06 + draw_track_preview((uint8**)trackDesign->preview); + + trackDesign->track_td6.cost = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_COST, money32); + trackDesign->track_td6.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; + } + + // Set preview to correct preview image based on rotation + if (preview != NULL) + *preview = trackDesign->preview[RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8)]; + + return trackDesign; +} + +void window_track_list_format_name(char *dst, const char *src, char colour, char quotes) +{ + if (colour != 0) + *dst++ = colour; + + if (quotes != 0) + *dst++ = FORMAT_OPENQUOTES; + + while (*src != '.' && *src != 0) { + *dst++ = *src++; + } + + if (quotes != 0) + *dst++ = FORMAT_ENDQUOTES; + + *dst = 0; +} + + +/** +* +* rct2: 0x006D40B2 +* returns 0 for copy fail, 1 for success, 2 for file exists. +*/ +int install_track(char* source_path, char* dest_name){ + + // Make a copy of the track name (no extension) + char track_name[MAX_PATH] = { 0 }; + char* dest = track_name; + char* dest_name_pointer = dest_name; + while (*dest_name_pointer != '.') *dest++ = *dest_name_pointer++; + + // Check if .TD4 file exists under that name + char* temp_extension_pointer = dest; + strcat(track_name, ".TD4"); + + char dest_path[MAX_PATH]; + subsitute_path(dest_path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), track_name); + + if (platform_file_exists(dest_path)) + return 2; + + // Allow a concat onto the track_name but before extension + *temp_extension_pointer = '\0'; + + // Check if .TD6 file exists under that name + strcat(track_name, ".TD6"); + + subsitute_path(dest_path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), track_name); + + if (platform_file_exists(dest_path)) + return 2; + + // Set path for actual copy + subsitute_path(dest_path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), dest_name); + + return platform_file_copy(source_path, dest_path); +} + +/* rct2: 0x006D13FE */ +void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp){ + int x = *eax; + int y = *ecx; + int z = *edi; + uint8 flags = *ebx; + + RCT2_GLOBAL(0x009DEA5E, sint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, sint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, sint16) = z; + + if (!(flags & (1 << 3))){ + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode){ + RCT2_GLOBAL(0x00141E9AC, rct_string_id) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + rct_object_entry* ride_object = &track_design->vehicle_object; + + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(ride_object, &entry_type, &entry_index)){ + entry_index = 0xFF; + } + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 988; + int rideIndex = 0; + { + int _eax = 0, + _ebx = GAME_COMMAND_FLAG_APPLY, + _ecx = 0, + _edx = track_design->type | (entry_index << 8), + _esi = GAME_COMMAND_6, + _edi = 0, + _ebp = 0; + game_do_command_p(GAME_COMMAND_6, &_eax, &_ebx, &_ecx, &_edx, &_esi, &_edi, &_ebp); + if (_ebx == MONEY32_UNDEFINED){ + *ebx = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 0; + RCT2_GLOBAL(0x00F44121, money32) = MONEY32_UNDEFINED; + return; + } + rideIndex = _edi & 0xFF; + } + + money32 cost = 0; + if (!(flags & GAME_COMMAND_FLAG_APPLY)){ + RCT2_GLOBAL(0x00F44150, uint8) = 0; + cost = sub_6D01B3(1, rideIndex, x, y, z); + if (RCT2_GLOBAL(0x00F4414E, uint8) & (1 << 1)){ + RCT2_GLOBAL(0x00F44150, uint8) |= 1 << 7; + cost = sub_6D01B3(0x81, rideIndex, x, y, z); + } + } + else{ + uint8 bl = 0; + if (flags & (1 << 6)){ + bl = 4; + } + else{ + bl = 2; + } + bl |= RCT2_GLOBAL(0x00F44150, uint8); + cost = sub_6D01B3(bl, rideIndex, x, y, z); + } + + if (cost == MONEY32_UNDEFINED || + !(flags & GAME_COMMAND_FLAG_APPLY)){ + rct_string_id error_reason = RCT2_GLOBAL(0x00141E9AC, rct_string_id); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, rideIndex, GAME_COMMAND_7, 0, 0); + *ebx = cost; + RCT2_GLOBAL(0x00141E9AC, rct_string_id) = error_reason; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 0; + RCT2_GLOBAL(0x00F44121, money32) = cost; + return; + } + + if (entry_index != 0xFF){ + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (2 << 8), 0, rideIndex | (entry_index << 8), GAME_COMMAND_9, 0, 0); + } + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->ride_mode << 8), 0, rideIndex | (0 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (0 << 8), 0, rideIndex | (track_design->number_of_trains << 8), GAME_COMMAND_9, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (1 << 8), 0, rideIndex | (track_design->number_of_cars_per_train << 8), GAME_COMMAND_9, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->depart_flags << 8), 0, rideIndex | (1 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->min_waiting_time << 8), 0, rideIndex | (2 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->max_waiting_time << 8), 0, rideIndex | (3 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->var_50 << 8), 0, rideIndex | (4 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | ((track_design->lift_hill_speed_num_circuits & 0x1F) << 8), 0, rideIndex | (8 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + uint8 num_circuits = track_design->lift_hill_speed_num_circuits >> 5; + if (num_circuits == 0) num_circuits = 1; + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (num_circuits << 8), 0, rideIndex | (9 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + rct_ride* ride = GET_RIDE(rideIndex); + + ride->lifecycle_flags |= RIDE_LIFECYCLE_18; + + if (track_design->var_6C & (1 << 31)){ + ride->lifecycle_flags |= RIDE_LIFECYCLE_SIX_FLAGS; + } + + ride->colour_scheme_type = track_design->version_and_colour_scheme & 3; + + uint8 version = track_design->version_and_colour_scheme >> 2; + if (version >= 2){ + ride->entrance_style = track_design->entrance_style; + } + + if (version > 1){ + for (int i = 0; i < 4; ++i){ + ride->track_colour_main[i] = track_design->track_spine_colour[i]; + ride->track_colour_additional[i] = track_design->track_rail_colour[i]; + ride->track_colour_supports[i] = track_design->track_support_colour[i]; + } + } + else{ + for (int i = 0; i < 4; ++i){ + ride->track_colour_main[i] = track_design->track_spine_colour_rct1; + ride->track_colour_additional[i] = track_design->track_rail_colour_rct1; + ride->track_colour_supports[i] = track_design->track_support_colour_rct1; + } + } + + for (int i = 0; i < 32; ++i){ + ride->vehicle_colours[i].body_colour = track_design->vehicle_colours[i].body_colour; + ride->vehicle_colours[i].trim_colour = track_design->vehicle_colours[i].trim_colour; + ride->vehicle_colours_extended[i] = track_design->vehicle_additional_colour[i]; + } + + ride_set_name(rideIndex, RCT2_ADDRESS(0x009E3504,const char)); + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 0; + *ebx = RCT2_GLOBAL(0x00F44121, money32); + *edi = rideIndex; +} + +/** + * + * rct2: 0x006D3026 + */ +void track_save_reset_scenery() +{ + rct_map_element **savedMapElements = (rct_map_element**)0x00F63674; + + RCT2_GLOBAL(0x009DA193, uint8) = 255; + savedMapElements[0] = (rct_map_element*)0xFFFFFFFF; + gfx_invalidate_screen(); +} + +/** + * + * rct2: 0x006D303D + */ +void track_save_select_nearby_scenery(int rideIndex) +{ + rct_map_element *mapElement; + + for (int y = 0; y < 256; y++) { + for (int x = 0; x < 256; x++) { + mapElement = map_get_first_element_at(x, y); + do { + if (track_save_should_select_scenery_around(rideIndex, mapElement)) { + track_save_select_nearby_scenery_for_tile(rideIndex, x, y); + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } + gfx_invalidate_screen(); +} + +static bool track_save_should_select_scenery_around(int rideIndex, rct_map_element *mapElement) +{ + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + if ((mapElement->type & 1) && mapElement->properties.path.addition_status == rideIndex) + return true; + break; + case MAP_ELEMENT_TYPE_TRACK: + if (mapElement->properties.track.ride_index == rideIndex) + return true; + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_RIDE_ENTRANCE) + break; + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_RIDE_EXIT) + break; + if (mapElement->properties.entrance.ride_index == rideIndex) + return true; + break; + } + return false; +} + +static void track_save_select_nearby_scenery_for_tile(int rideIndex, int cx, int cy) +{ + rct_map_element *mapElement; + + for (int y = cy - 1; y <= cy + 1; y++) { + for (int x = cx - 1; x <= cx + 1; x++) { + mapElement = map_get_first_element_at(x, y); + do { + int mapElementSelectType = 0; + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + if (!(mapElement->type & 1)) + mapElementSelectType = 6; + else if (mapElement->properties.path.addition_status == rideIndex) + mapElementSelectType = 6; + break; + case MAP_ELEMENT_TYPE_SCENERY: + mapElementSelectType = 5; + break; + case MAP_ELEMENT_TYPE_FENCE: + mapElementSelectType = 9; + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + mapElementSelectType = 10; + break; + } + + if (mapElementSelectType != 0) { + bool mapElementAlreadySelected = false; + rct_map_element **savedMapElement = (rct_map_element**)0x00F63674; + while (*savedMapElement != (rct_map_element*)0xFFFFFFFF) { + if (*savedMapElement == mapElement) { + mapElementAlreadySelected = true; + break; + } + savedMapElement++; + } + + if (!mapElementAlreadySelected) + track_save_add_map_element(mapElementSelectType, x * 32, y * 32, mapElement); + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } +} + +/** + * + * rct2: 0x006D2B3C + */ +static void track_save_add_map_element(int mapElementSelectType, int x, int y, rct_map_element *mapElement) +{ + RCT2_CALLPROC_X(0x006D2B3C, x, mapElementSelectType, y, (int)mapElement, 0, 0, 0); +} diff --git a/src/ride/track.h b/src/ride/track.h index e55e598c4f..dc5e8acb64 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -22,6 +22,7 @@ #define _TRACK_H_ #include "../common.h" +#include "../object.h" #include "ride.h" typedef struct { @@ -34,6 +35,74 @@ typedef struct { uint8 pad[2]; } rct_trackdefinition; +/** +* Size: 0x0A +*/ +typedef struct { + uint8 var_00; + sint16 x; // 0x01 + sint16 y; // 0x03 + sint16 z; + uint8 pad_07; + uint8 var_08; + uint8 var_09; +} rct_preview_track; + +/** +* Size: 0x04 +*/ +typedef struct { + union { + uint32 all; + struct { + sint8 x; + sint8 y; + union{ + uint16 maze_entry; + struct{ + uint8 unk_2; + uint8 type; + }; + }; + }; + }; +} rct_maze_element; + +/* Size: 0x02 */ +typedef struct{ + uint8 type; + uint8 flags; +}rct_track_element; + +/* Track Scenery entry size: 0x16 */ +typedef struct{ + rct_object_entry scenery_object; // 0x00 + sint8 x; // 0x10 + sint8 y; // 0x11 + sint8 z; // 0x12 + uint8 flags; // 0x13 direction quadrant tertiary colour + uint8 primary_colour; // 0x14 + uint8 secondary_colour; // 0x15 +}rct_track_scenery; + +/* Track Entrance entry size: 0x6 */ +typedef struct{ + sint8 z; + uint8 direction; // 0x01 + sint16 x; // 0x02 + sint16 y; // 0x04 +}rct_track_entrance; + +enum{ + TRACK_ELEMENT_FLAG_CHAIN_LIFT = (1<<7), + TRACK_ELEMENT_FLAG_INVERTED = (1<<6), + TRACK_ELEMENT_FLAG_TERMINAL_STATION = (1<<3), +}; + +#define TRACK_ELEMENT_FLAG_MAGNITUDE_MASK 0x0F +#define TRACK_ELEMENT_FLAG_COLOUR_MASK 0x30 +#define TRACK_ELEMENT_FLAG_STATION_NO_MASK 0x02 + #define TRACK_PREVIEW_IMAGE_SIZE (370 * 217) /** @@ -42,18 +111,44 @@ typedef struct { */ typedef struct { uint8 type; // 0x00 - uint8 pad_01; - money32 cost; // 0x02 - uint8 var_06; - uint8 var_07; - uint8 pad_08[0x42]; - uint8 total_air_time; // 0x4A - uint8 pad_4B[0x06]; - uint8 max_speed; // 0x51 - uint8 average_speed; // 0x52 + uint8 vehicle_type; + union{ + // After loading the track this is converted to + // a cost but before its a flags register + money32 cost; // 0x02 + uint32 flags; // 0x02 + }; + union{ + // After loading the track this is converted to + // a flags register + uint8 ride_mode; // 0x06 + uint8 track_flags; // 0x06 + }; + uint8 version_and_colour_scheme; // 0x07 0b0000_VVCC + rct_vehicle_colour vehicle_colours[32]; // 0x08 + union{ + uint8 pad_48; + uint8 track_spine_colour_rct1; // 0x48 + }; + union{ + uint8 entrance_style; // 0x49 + uint8 track_rail_colour_rct1; // 0x49 + }; + union{ + uint8 total_air_time; // 0x4A + uint8 track_support_colour_rct1; // 0x4A + }; + uint8 depart_flags; // 0x4B + uint8 number_of_trains; // 0x4C + uint8 number_of_cars_per_train; // 0x4D + uint8 min_waiting_time; // 0x4E + uint8 max_waiting_time; // 0x4F + uint8 var_50; + sint8 max_speed; // 0x51 + sint8 average_speed; // 0x52 uint16 ride_length; // 0x53 uint8 max_positive_vertical_g; // 0x55 - uint8 max_negitive_vertical_g; // 0x56 + sint8 max_negative_vertical_g; // 0x56 uint8 max_lateral_g; // 0x57 union { uint8 inversions; // 0x58 @@ -64,15 +159,24 @@ typedef struct { uint8 excitement; // 0x5B uint8 intensity; // 0x5C uint8 nausea; // 0x5D - uint8 pad_5E[0x0E]; + money16 upkeep_cost; // 0x5E + uint8 track_spine_colour[4]; // 0x60 + uint8 track_rail_colour[4]; // 0x64 + uint8 track_support_colour[4]; // 0x68 uint32 var_6C; - uint8 pad_70[0x10]; + rct_object_entry vehicle_object; // 0x70 uint8 space_required_x; // 0x80 uint8 space_required_y; // 0x81 - uint8 pad_82[0x21]; + uint8 vehicle_additional_colour[32]; // 0x82 + uint8 lift_hill_speed_num_circuits; // 0xA2 0bCCCL_LLLL +} rct_track_td6; + +typedef struct{ + rct_track_td6 track_td6; uint8 preview[4][TRACK_PREVIEW_IMAGE_SIZE]; // 0xA3 } rct_track_design; + enum { TRACK_NONE = 0, @@ -130,8 +234,215 @@ enum { TRACK_CORKSCREW_DOWN = 224 }; +enum { + TRACK_ELEM_FLAT, + TRACK_ELEM_END_STATION, + TRACK_ELEM_BEGIN_STATION, + TRACK_ELEM_MIDDLE_STATION, + TRACK_ELEM_25_DEG_UP, + TRACK_ELEM_60_DEG_UP, + TRACK_ELEM_FLAT_TO_25_DEG_UP, + TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP, + TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP, + TRACK_ELEM_25_DEG_UP_TO_FLAT, + TRACK_ELEM_25_DEG_DOWN, + TRACK_ELEM_60_DEG_DOWN, + TRACK_ELEM_FLAT_TO_25_DEG_DOWN, + TRACK_ELEM_25_DEG_DOWN_TO_60_DEG_DOWN, + TRACK_ELEM_60_DEG_DOWN_TO_25_DEG_DOWN, + TRACK_ELEM_25_DEG_DOWN_TO_FLAT, + TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES, + TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES, + TRACK_ELEM_FLAT_TO_LEFT_BANK, + TRACK_ELEM_FLAT_TO_RIGHT_BANK, + TRACK_ELEM_LEFT_BANK_TO_FLAT, + TRACK_ELEM_RIGHT_BANK_TO_FLAT, + TRACK_ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES, + TRACK_ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES, + TRACK_ELEM_LEFT_BANK_TO_25_DEG_UP, + TRACK_ELEM_RIGHT_BANK_TO_25_DEG_UP, + TRACK_ELEM_25_DEG_UP_TO_LEFT_BANK, + TRACK_ELEM_25_DEG_UP_TO_RIGHT_BANK, + TRACK_ELEM_LEFT_BANK_TO_25_DEG_DOWN, + TRACK_ELEM_RIGHT_BANK_TO_25_DEG_DOWN, + TRACK_ELEM_25_DEG_DOWN_TO_LEFT_BANK, + TRACK_ELEM_25_DEG_DOWN_TO_RIGHT_BANK, + TRACK_ELEM_LEFT_BANK, + TRACK_ELEM_RIGHT_BANK, + TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP, + TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP, + TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN, + TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN, + TRACK_ELEM_S_BEND_LEFT, + TRACK_ELEM_S_BEND_RIGHT, + TRACK_ELEM_LEFT_VERTICAL_LOOP, + TRACK_ELEM_RIGHT_VERTICAL_LOOP, + TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES, + TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES, + TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_BANK, + TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK, + TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP, + TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP, + TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN, + TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN, + TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE, + TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE, + TRACK_ELEM_LEFT_TWIST_DOWN_TO_UP, + TRACK_ELEM_RIGHT_TWIST_DOWN_TO_UP, + TRACK_ELEM_LEFT_TWIST_UP_TO_DOWN, + TRACK_ELEM_RIGHT_TWIST_UP_TO_DOWN, + TRACK_ELEM_HALF_LOOP_UP, + TRACK_ELEM_HALF_LOOP_DOWN, + TRACK_ELEM_LEFT_CORKSCREW_UP, + TRACK_ELEM_RIGHT_CORKSCREW_UP, + TRACK_ELEM_LEFT_CORKSCREW_DOWN, + TRACK_ELEM_RIGHT_CORKSCREW_DOWN, + TRACK_ELEM_FLAT_TO_60_DEG_UP, + TRACK_ELEM_60_DEG_UP_TO_FLAT, + TRACK_ELEM_FLAT_TO_60_DEG_DOWN, + TRACK_ELEM_60_DEG_DOWN_TO_FLAT, + TRACK_ELEM_TOWER_BASE, + TRACK_ELEM_TOWER_SECTION, + TRACK_ELEM_FLAT_COVERED, + TRACK_ELEM_25_DEG_UP_COVERED, + TRACK_ELEM_60_DEG_UP_COVERED, + TRACK_ELEM_FLAT_TO_25_DEG_UP_COVERED, + TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED, + TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED, + TRACK_ELEM_25_DEG_UP_TO_FLAT_COVERED, + TRACK_ELEM_25_DEG_DOWN_COVERED, + TRACK_ELEM_60_DEG_DOWN_COVERED, + TRACK_ELEM_FLAT_TO_25_DEG_DOWN_COVERED, + TRACK_ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED, + TRACK_ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED, + TRACK_ELEM_25_DEG_DOWN_TO_FLAT_COVERED, + TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED, + TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED, + TRACK_ELEM_S_BEND_LEFT_COVERED, + TRACK_ELEM_S_BEND_RIGHT_COVERED, + TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED, + TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED, + TRACK_ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL, + TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL, + TRACK_ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL, + TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL, + TRACK_ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE, + TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE, + TRACK_ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE, + TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE, + TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP, + TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP, + TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN, + TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN, + TRACK_ELEM_BRAKES, + TRACK_ELEM_ROTATION_CONTROL_TOGGLE, + TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP, + TRACK_ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP, + TRACK_ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP, + TRACK_ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN, + TRACK_ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN, + TRACK_ELEM_LEFT_QUARTER_HELIX_LARGE_UP, + TRACK_ELEM_RIGHT_QUARTER_HELIX_LARGE_UP, + TRACK_ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN, + TRACK_ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN, + TRACK_ELEM_25_DEG_UP_LEFT_BANKED, + TRACK_ELEM_25_DEG_UP_RIGHT_BANKED, + TRACK_ELEM_WATERFALL, + TRACK_ELEM_RAPIDS, + TRACK_ELEM_ON_RIDE_PHOTO, + TRACK_ELEM_25_DEG_DOWN_LEFT_BANKED, + TRACK_ELEM_25_DEG_DOWN_RIGHT_BANKED, + TRACK_ELEM_WATER_SPLASH, + TRACK_ELEM_FLAT_TO_60_DEG_UP_LONG_BASE, + TRACK_ELEM_60_DEG_UP_TO_FLAT_LONG_BASE, + TRACK_ELEM_WHIRLPOOL, + TRACK_ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE, + TRACK_ELEM_60_DEG_UP_TO_FLAT_LONG_BASE_122, + TRACK_ELEM_CABLE_LIFT_HILL, + TRACK_ELEM_REVERSE_WHOA_BELLY_SLOPE, + TRACK_ELEM_REVERSE_WHOA_BELLY_VERTICAL, + TRACK_ELEM_90_DEG_UP, + TRACK_ELEM_90_DEG_DOWN, + TRACK_ELEM_60_DEG_UP_TO_90_DEG_UP, + TRACK_ELEM_90_DEG_DOWN_TO_60_DEG_DOWN, + TRACK_ELEM_90_DEG_UP_TO_60_DEG_UP, + TRACK_ELEM_60_DEG_DOWN_TO_90_DEG_DOWN, + TRACK_ELEM_BRAKE_FOR_DROP, + TRACK_ELEM_LEFT_EIGHTH_TO_DIAG, + TRACK_ELEM_RIGHT_EIGHTH_TO_DIAG, + TRACK_ELEM_LEFT_EIGHTH_TO_ORTHOGONAL, + TRACK_ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL, + TRACK_ELEM_LEFT_EIGHTH_BANK_TO_DIAG, + TRACK_ELEM_RIGHT_EIGHTH_BANK_TO_DIAG, + TRACK_ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL, + TRACK_ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL, + TRACK_ELEM_DIAG_FLAT, + TRACK_ELEM_DIAG_25_DEG_UP, + TRACK_ELEM_DIAG_60_DEG_UP, + TRACK_ELEM_DIAG_FLAT_TO_25_DEG_UP, + TRACK_ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP, + TRACK_ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP, + TRACK_ELEM_DIAG_25_DEG_UP_TO_FLAT, + TRACK_ELEM_DIAG_25_DEG_DOWN, + TRACK_ELEM_DIAG_60_DEG_DOWN, + TRACK_ELEM_DIAG_FLAT_TO_25_DEG_DOWN, + TRACK_ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN, + TRACK_ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN, + TRACK_ELEM_DIAG_25_DEG_DOWN_TO_FLAT, + TRACK_ELEM_DIAG_FLAT_TO_60_DEG_UP, + TRACK_ELEM_DIAG_60_DEG_UP_TO_FLAT, + TRACK_ELEM_DIAG_FLAT_TO_60_DEG_DOWN, + TRACK_ELEM_DIAG_60_DEG_DOWN_TO_FLAT, + TRACK_ELEM_DIAG_FLAT_TO_LEFT_BANK, + TRACK_ELEM_DIAG_FLAT_TO_RIGHT_BANK, + TRACK_ELEM_DIAG_LEFT_BANK_TO_FLAT, + TRACK_ELEM_DIAG_RIGHT_BANK_TO_FLAT, + TRACK_ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP, + TRACK_ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP, + TRACK_ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK, + TRACK_ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK, + TRACK_ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN, + TRACK_ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN, + TRACK_ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK, + TRACK_ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK, + TRACK_ELEM_DIAG_LEFT_BANK, + TRACK_ELEM_DIAG_RIGHT_BANK, + TRACK_ELEM_LOG_FLUME_REVERSER, + TRACK_ELEM_SPINNING_TUNNEL, + TRACK_ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN, + TRACK_ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN, + TRACK_ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP, + TRACK_ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP, + TRACK_ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP, + TRACK_ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP, + TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK, + TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK, + TRACK_ELEM_POWERED_LIFT, + TRACK_ELEM_LEFT_LARGE_HALF_LOOP_UP, + TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_UP, + TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_DOWN, + TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN +}; + +extern const rct_trackdefinition *gTrackDefinitions; + void track_load_list(ride_list_item item); int sub_67726A(const char *path); rct_track_design *track_get_info(int index, uint8** preview); +rct_track_design *temp_track_get_info(char* path, uint8** preview); +rct_track_td6* load_track_design(const char *path); +int track_rename(const char *text); +int track_delete(); +void track_mirror(); +void reset_track_list_cache(); +int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b); +int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z); +int save_track_design(uint8 rideIndex); +int install_track(char* source_path, char* dest_name); +void window_track_list_format_name(char *dst, const char *src, char colour, char quotes); +void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); -#endif \ No newline at end of file +void track_save_reset_scenery(); +void track_save_select_nearby_scenery(int rideIndex); + +#endif diff --git a/src/ride/track_data.c b/src/ride/track_data.c new file mode 100644 index 0000000000..636cb95522 --- /dev/null +++ b/src/ride/track_data.c @@ -0,0 +1,280 @@ +/***************************************************************************** +* 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 . +*****************************************************************************/ + +#include "track_data.h" + +const rct_track_coordinates TrackCoordinates[256] = { + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 0, 64, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 32, 0, 0 }, + { 0, 0, 0, 32, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 64, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 32, 0, 0, 0 }, + { 0, 0, 32, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 3, 0, 0, -64, -64 }, + { 0, 1, 0, 0, -64, 64 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 3, 0, 0, -64, -64 }, + { 0, 1, 0, 0, -64, 64 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 3, 0, 64, -64, -64 }, + { 0, 1, 0, 64, -64, 64 }, + { 0, 3, 64, 0, -64, -64 }, + { 0, 1, 64, 0, -64, 64 }, + { 0, 0, 0, 0, -64, -32 }, + { 0, 0, 0, 0, -64, 32 }, + { 0, 0, 0, 0, -32, -32 }, + { 0, 0, 0, 0, -32, 32 }, + { 0, 3, 0, 0, -32, -32 }, + { 0, 1, 0, 0, -32, 32 }, + { 0, 3, 0, 0, -32, -32 }, + { 0, 1, 0, 0, -32, 32 }, + { 0, 3, 0, 32, -32, -32 }, + { 0, 1, 0, 32, -32, 32 }, + { 0, 3, 32, 0, -32, -32 }, + { 0, 1, 32, 0, -32, 32 }, + { 0, 3, 0, 0, 0, 0 }, + { 0, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 16, -64, 0 }, + { 0, 0, 0, 16, -64, 0 }, + { 0, 0, 0, -16, -64, 0 }, + { 0, 0, 0, -16, -64, 0 }, + { 0, 2, 0, 152, -32, 0 }, + { 0, 2, 0, -152, 32, 0 }, + { 0, 3, 0, 80, -32, -32 }, + { 0, 1, 0, 80, -32, 32 }, + { 0, 3, 0, -80, -32, -32 }, + { 0, 1, 0, -80, -32, 32 }, + { 0, 0, 0, 24, 0, 0 }, + { 0, 0, 0, 24, 0, 0 }, + { 0, 0, 24, 0, 0, 0 }, + { 0, 0, 24, 0, 0, 0 }, + { 0, 0, 0, 96, 32, 0 }, + { 0, 0, 0, 32, 32, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 0, 64, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 32, 0, 0 }, + { 0, 0, 0, 32, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 64, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 32, 0, 0, 0 }, + { 0, 0, 32, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 3, 0, 0, -64, -64 }, + { 0, 1, 0, 0, -64, 64 }, + { 0, 0, 0, 0, -64, -32 }, + { 0, 0, 0, 0, -64, 32 }, + { 0, 3, 0, 0, -32, -32 }, + { 0, 1, 0, 0, -32, 32 }, + { 0, 2, 0, 16, 0, -96 }, + { 0, 2, 0, 16, 0, 96 }, + { 0, 2, 16, 0, 0, -96 }, + { 0, 2, 16, 0, 0, 96 }, + { 0, 2, 0, 16, 0, -160 }, + { 0, 2, 0, 16, 0, 160 }, + { 0, 2, 16, 0, 0, -160 }, + { 0, 2, 16, 0, 0, 160 }, + { 0, 3, 0, 64, 0, 0 }, + { 0, 1, 0, 64, 0, 0 }, + { 0, 3, 64, 0, 0, 0 }, + { 0, 1, 64, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 3, 0, 16, -64, -64 }, + { 0, 1, 0, 16, -64, 64 }, + { 0, 3, 16, 0, -64, -64 }, + { 0, 1, 16, 0, -64, 64 }, + { 0, 3, 0, 16, -64, -64 }, + { 0, 1, 0, 16, -64, 64 }, + { 0, 3, 16, 0, -64, -64 }, + { 0, 1, 16, 0, -64, 64 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 16, 16, -128, 0 }, + { 0, 0, 0, 88, -96, 0 }, + { 0, 0, 0, 88, -96, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 88, 0, -96, 0 }, + { 0, 0, 88, 0, -96, 0 }, + { 0, 0, 0, -96, -96, 0 }, + { 0, 0, 0, 240, -160, 0 }, + { 0, 0, 0, 80, 32, 0 }, + { 0, 0, 0, 32, 32, 0 }, + { 0, 0, 32, 0, 32, 0 }, + { 0, 0, 0, 56, 32, 0 }, + { 0, 0, 56, 0, 0, 0 }, + { 0, 0, 0, 56, 0, 0 }, + { 0, 0, 56, 0, 32, 0 }, + { 0, 0, 24, 0, 0, 0 }, + { 0, 7, 0, 0, -64, -32 }, + { 0, 4, 0, 0, -64, 32 }, + { 4, 0, 0, 0, -64, 32 }, + { 4, 1, 0, 0, -32, 64 }, + { 0, 7, 0, 0, -64, -32 }, + { 0, 4, 0, 0, -64, 32 }, + { 4, 0, 0, 0, -64, 32 }, + { 4, 1, 0, 0, -32, 64 }, + { 4, 4, 0, 0, -32, 32 }, + { 4, 4, 0, 16, -32, 32 }, + { 4, 4, 0, 64, -32, 32 }, + { 4, 4, 0, 8, -32, 32 }, + { 4, 4, 0, 32, -32, 32 }, + { 4, 4, 0, 32, -32, 32 }, + { 4, 4, 0, 8, -32, 32 }, + { 4, 4, 16, 0, -32, 32 }, + { 4, 4, 64, 0, -32, 32 }, + { 4, 4, 8, 0, -32, 32 }, + { 4, 4, 32, 0, -32, 32 }, + { 4, 4, 32, 0, -32, 32 }, + { 4, 4, 8, 0, -32, 32 }, + { 4, 4, 0, 24, -32, 32 }, + { 4, 4, 0, 24, -32, 32 }, + { 4, 4, 24, 0, -32, 32 }, + { 4, 4, 24, 0, -32, 32 }, + { 4, 4, 0, 0, -32, 32 }, + { 4, 4, 0, 0, -32, 32 }, + { 4, 4, 0, 0, -32, 32 }, + { 4, 4, 0, 0, -32, 32 }, + { 4, 4, 0, 8, -32, 32 }, + { 4, 4, 0, 8, -32, 32 }, + { 4, 4, 0, 8, -32, 32 }, + { 4, 4, 0, 8, -32, 32 }, + { 4, 4, 8, 0, -32, 32 }, + { 4, 4, 8, 0, -32, 32 }, + { 4, 4, 8, 0, -32, 32 }, + { 4, 4, 8, 0, -32, 32 }, + { 4, 4, 0, 0, -32, 32 }, + { 4, 4, 0, 0, -32, 32 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 32, -64, 0 }, + { 0, 0, 0, 32, -64, 0 }, + { 0, 0, 0, -32, -64, 0 }, + { 0, 0, 0, -32, -64, 0 }, + { 0, 3, 0, 24, -32, -32 }, + { 0, 1, 0, 24, -32, 32 }, + { 0, 3, 24, 0, -32, -32 }, + { 0, 1, 24, 0, -32, 32 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 2, 0, 280, -64, -32 }, + { 0, 2, 0, 280, -64, 32 }, + { 0, 2, 0, -280, 64, -32 }, + { 0, 2, 0, -280, 64, 32 }, + { 0, 0, 0, -16, -64, 0 }, + { 0, 0, 0, -16, -64, 0 }, + { 0, 0, 0, 16, -64, 0 }, + { 0, 0, 0, 16, -64, 0 }, + { 0, 2, 0, 120, -32, 0 }, + { 0, 2, 0, -120, 32, 0 }, + { 0, 3, 0, 48, -32, -32 }, + { 0, 1, 0, 48, -32, 32 }, + { 0, 3, 0, -48, -32, -32 }, + { 0, 1, 0, -48, -32, 32 }, + { 0, 2, 0, 32, 0, 0 }, + { 0, 2, 0, -32, 0, 0 }, + { 0, 0, 0, 0, -160, 0 }, + { 0, 0, 0, 0, -160, 0 }, + { 0, 0, 0, 0, -32, 0 }, + { 0, 0, 0, 0, -32, 0 }, + { 0, 0, 0, 0, -32, 0 }, + { 0, 1, 0, 0, -32, 32 }, + { 0, 3, 0, 0, -32, -32 }, + { 0, 2, 0, -96, -96, 0 }, + { 0, 2, 0, 128, 64, 0 }, + { 0, 2, 0, -128, -96, 0 }, + { 0, 3, 0, 16, -32, -32 }, + { 0, 1, 0, 16, -32, 32 }, + { 0, 0, 0, 0, -64, 0 }, + { 0, 0, 0, 0, -64, 0 }, + { 0, 0, 0, 0, -32, 0 }, + { 0, 0, 80, 0, 32, 0 }, + { 0, 0, 240, 0, -160, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 3, 0, 32, -32, -32 }, + { 0, 1, 0, 32, -32, 32 }, + { 0, 3, 32, 0, -32, -32 }, + { 0, 1, 32, 0, -32, 32 }, + { 0, 3, 0, 64, -64, -64 }, + { 0, 1, 0, 64, -64, 64 }, + { 0, 3, 64, 0, -64, -64 }, + { 0, 1, 64, 0, -64, 64 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 0, 16, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 16, 0, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 0, 8, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 0, 8, 0, 0, 0 }, + { 0, 3, 0, 96, 0, 32 }, + { 0, 1, 0, 96, 0, -32 }, + { 0, 3, 96, 0, 0, 32 }, + { 0, 1, 96, 0, 0, -32 }, + { 0, 2, 0, 96, 64, 0 }, + { 0, 2, 0, -128, -96, 0 }, + { 0, 2, 0, 128, 64, 0 } +}; \ No newline at end of file diff --git a/src/ride/track_data.h b/src/ride/track_data.h new file mode 100644 index 0000000000..c10ad9bd3d --- /dev/null +++ b/src/ride/track_data.h @@ -0,0 +1,33 @@ +/***************************************************************************** +* 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 . +*****************************************************************************/ +#include "../common.h" + +/* size 0x0A */ +typedef struct{ + sint8 rotation_negative; // 0x00 + sint8 rotation_positive; // 0x01 + sint16 z_negative; // 0x02 + sint16 z_positive; // 0x04 + sint16 x; // 0x06 + sint16 y; // 0x08 +}rct_track_coordinates; + +// 0x009968BB, 0x009968BC, 0x009968BD, 0x009968BF, 0x009968C1, 0x009968C3 +extern const rct_track_coordinates TrackCoordinates[256]; \ No newline at end of file diff --git a/src/ride/vehicle.c b/src/ride/vehicle.c index 19b32d97e5..3536ea1985 100644 --- a/src/ride/vehicle.c +++ b/src/ride/vehicle.c @@ -35,9 +35,9 @@ static void vehicle_update(rct_vehicle *vehicle); */ void vehicle_update_sound_params(rct_vehicle* vehicle) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) && (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 4) || RCT2_GLOBAL(0x0141F570, uint8) == 6)) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) || RCT2_GLOBAL(0x0141F570, uint8) == 6)) { if (vehicle->sound1_id != (uint8)-1 || vehicle->sound2_id != (uint8)-1) { - if (vehicle->sprite_left != 0x8000) { + if (vehicle->sprite_left != (sint16)0x8000) { RCT2_GLOBAL(0x009AF5A0, sint16) = vehicle->sprite_left; RCT2_GLOBAL(0x009AF5A2, sint16) = vehicle->sprite_top; RCT2_GLOBAL(0x009AF5A4, sint16) = vehicle->sprite_right; @@ -99,9 +99,8 @@ void vehicle_update_sound_params(rct_vehicle* vehicle) sint32 v19 = vehicle->velocity; - int testaddr = (vehicle->var_31 * 0x65); - testaddr += (int)RCT2_ADDRESS(0x009ACFA4, rct_ride_type*)[vehicle->var_D6]; - uint8 test = ((uint8*)testaddr)[0x74]; + rct_ride_type* ride_type = GET_RIDE_ENTRY(vehicle->ride_subtype); + uint8 test = ride_type->vehicles[vehicle->vehicle_type].var_5A; if (test & 1) { v19 *= 2; @@ -117,7 +116,7 @@ void vehicle_update_sound_params(rct_vehicle* vehicle) i->frequency = (uint16)v19; i->id = vehicle->sprite_index; i->volume = 0; - if (vehicle->x != 0x8000) { + if (vehicle->x != (sint16)0x8000) { int tile_idx = (((vehicle->y & 0xFFE0) * 256) + (vehicle->x & 0xFFE0)) / 32; rct_map_element* map_element; for (map_element = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[tile_idx]; map_element->type & MAP_ELEMENT_TYPE_MASK; map_element++); @@ -230,7 +229,7 @@ void vehicle_sounds_update() vehicle_sound->id = (uint16)-1; } label26: - 1; + ; } //for (rct_vehicle_sound_params* vehicle_sound_params = &RCT2_GLOBAL(0x00F438B4, rct_vehicle_sound_params); ; vehicle_sound_params++) { @@ -305,7 +304,7 @@ void vehicle_sounds_update() while (vehicle_sound->id != (uint16)-1) { vehicle_sound++; i++; - if (i >= countof(gVehicleSoundList)/*i >= RCT2_GLOBAL(0x009AAC75, uint8)*/) { + if (i >= countof(gVehicleSoundList)/*i >= RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MAX_VEHICLE_SOUNDS, uint8)*/) { vehicle_sound_params = (rct_vehicle_sound_params*)((int)vehicle_sound_params + 10); goto label28; } @@ -535,7 +534,7 @@ void vehicle_sounds_update() } } label114: - 1; + ; } } } @@ -550,10 +549,10 @@ void vehicle_update_all() uint16 sprite_index; rct_vehicle *vehicle; - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) return; - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 4) && RCT2_GLOBAL(0x0141F570, uint8) != 6) + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && RCT2_GLOBAL(0x0141F570, uint8) != 6) return; @@ -633,4 +632,9 @@ rct_vehicle *vehicle_get_head(rct_vehicle *vehicle) } return vehicle; +} + +int vehicle_is_used_in_pairs(rct_vehicle *vehicle) +{ + return vehicle->num_seats & VEHICLE_SEAT_PAIR_FLAG; } \ No newline at end of file diff --git a/src/ride/vehicle.h b/src/ride/vehicle.h index 292e3f399d..866f52cc08 100644 --- a/src/ride/vehicle.h +++ b/src/ride/vehicle.h @@ -23,34 +23,50 @@ #include "../common.h" +/* size: 0x2 */ +typedef struct{ + uint8 body_colour; + uint8 trim_colour; +} rct_vehicle_colour; + typedef struct { uint8 sprite_identifier; // 0x00 uint8 var_01; - uint8 pad_02[0x02]; + uint16 next_in_quadrant; // 0x02 uint16 next; // 0x04 uint16 previous; // 0x06 uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... - uint8 pad_09; + // Height from center of sprite to bottom + uint8 sprite_height_negative; // 0x09 uint16 sprite_index; // 0x0A uint8 pad_0C[2]; sint16 x; // 0x0E sint16 y; // 0x10 sint16 z; // 0x12 - uint8 pad_14[0x02]; + // Width from center of sprite to edge + uint8 sprite_width; // 0x14 + // Height from center of sprite to top + uint8 sprite_height_positive; // 0x15 sint16 sprite_left; // 0x16 sint16 sprite_top; // 0x18 sint16 sprite_right; // 0x1A sint16 sprite_bottom; // 0x1C uint8 sprite_direction; // 0x1E - uint8 pad_1F[0x09]; + uint8 var_1F; + uint8 pad_20[0x08]; sint32 velocity; // 0x28 uint8 pad_2C[0x04]; uint8 ride; // 0x30 - uint8 var_31; + uint8 vehicle_type; // 0x31 uint8 pad_32[0x02]; uint16 var_34; sint16 var_36; - uint8 pad_38[0x06]; + //x related + uint16 var_38; + // y related + uint16 var_3A; + // z related + uint16 var_3C; uint16 next_vehicle_on_train; // 0x3E uint16 prev_vehicle_on_train; // 0x40 uint16 pad_42; @@ -58,14 +74,16 @@ typedef struct { uint16 var_46; uint16 var_48; uint8 pad_4A; - uint8 var_4B; + uint8 current_station; // 0x4B uint8 pad_4C[0x4]; uint8 status; // 0x50 uint8 var_51; uint16 peep[32]; // 0x52 - uint8 pad_92[0x21]; + uint8 peep_tshirt_colours[32]; // 0x92 + uint8 num_seats; // 0xB2 uint8 num_peeps; // 0xB3 - uint8 pad_B4[0x07]; + uint8 next_free_seat; // 0xB4 + uint8 pad_B5[0x06]; uint8 sound1_id; // 0xBB uint8 sound1_volume; // 0xBC uint8 sound2_id; // 0xBD @@ -78,10 +96,11 @@ typedef struct { uint8 var_CD; union { uint8 var_CE; - uint8 num_laps; // 0xCE + uint8 num_laps; // 0xCE }; - uint8 pad_CF[0x07]; - uint8 var_D6; + uint8 pad_CF[0x06]; + uint8 var_D5; + uint8 ride_subtype; // 0xD6 } rct_vehicle; enum { @@ -118,13 +137,16 @@ enum { VEHICLE_STATUS_STOPPED_BY_BLOCK_BRAKES }; +#define VEHICLE_SEAT_PAIR_FLAG 0x80 +#define VEHICLE_SEAT_NUM_MASK 0x7F + void vehicle_update_all(); int sub_6BC2F3(rct_vehicle* vehicle); void sub_6BB9FF(rct_vehicle* vehicle); void vehicle_sounds_update(); void vehicle_get_g_forces(rct_vehicle *vehicle, int *verticalG, int *lateralG); void vehicle_set_map_toolbar(rct_vehicle *vehicle); - +int vehicle_is_used_in_pairs(rct_vehicle *vehicle); rct_vehicle *vehicle_get_head(rct_vehicle *vehicle); /** Helper macro until rides are stored in this module. */ diff --git a/src/scenario.c b/src/scenario.c index 47a6de8f1d..01fa21a94c 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "addresses.h" +#include "config.h" #include "game.h" #include "interface/viewport.h" #include "localisation/date.h" @@ -29,6 +30,7 @@ #include "management/research.h" #include "management/news_item.h" #include "object.h" +#include "peep/staff.h" #include "platform/platform.h" #include "ride/ride.h" #include "scenario.h" @@ -37,7 +39,17 @@ #include "util/util.h" #include "world/map.h" #include "world/park.h" +#include "world/scenery.h" #include "world/sprite.h" +#include "world/water.h" + +static char _scenarioPath[MAX_PATH]; +static const char *_scenarioFileName; + +char gScenarioSaveName[MAX_PATH]; + +static int scenario_create_ducks(); +static void scenario_objective_check(); /** * Loads only the basic information from a scenario. @@ -62,10 +74,10 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in // Checks for a scenario string object (possibly for localisation) if ((info->entry.flags & 0xFF) != 255) { if (object_get_scenario_text(&info->entry)) { - int ebp = RCT2_GLOBAL(0x009ADAF8, uint32); - format_string(info->name, RCT2_GLOBAL(ebp, sint16), NULL); - format_string(info->details, RCT2_GLOBAL(ebp + 4, sint16), NULL); - RCT2_GLOBAL(0x009AA00C, uint8) = RCT2_GLOBAL(ebp + 6, uint8); + rct_stex_entry* stex_entry = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, rct_stex_entry*); + format_string(info->name, stex_entry->scenario_name, NULL); + format_string(info->details, stex_entry->details, NULL); + RCT2_GLOBAL(0x009AA00C, uint8) = stex_entry->var_06; object_free_scenario_text(); } } @@ -75,8 +87,8 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in } log_error("invalid scenario, %s", path); - // RCT2_GLOBAL(0x009AC31B, sint8) = -1; - // RCT2_GLOBAL(0x009AC31C, sint16) = 3011; + // RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, sint8) = -1; + // RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, sint16) = 3011; return 0; } @@ -98,8 +110,8 @@ int scenario_load(const char *path) if (file != NULL) { if (!sawyercoding_validate_checksum(file)) { fclose(file); - RCT2_GLOBAL(0x009AC31B, uint8) = 255; - RCT2_GLOBAL(0x009AC31C, uint16) = STR_FILE_CONTAINS_INVALID_DATA; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; log_error("failed to load scenario, invalid checksum"); return 0; @@ -162,12 +174,10 @@ int scenario_load(const char *path) set_load_objects_fail_reason(); return 0; } - // Check expansion pack - // RCT2_CALLPROC_EBPSAFE(0x006757E6); - RCT2_CALLPROC_EBPSAFE(0x006A9FC0); + reset_loaded_objects(); map_update_tile_pointers(); - reset_0x69EBE4();// RCT2_CALLPROC_EBPSAFE(0x0069EBE4); + reset_0x69EBE4(); return 1; } @@ -175,8 +185,8 @@ int scenario_load(const char *path) } log_error("failed to find scenario file."); - RCT2_GLOBAL(0x009AC31B, uint8) = 255; - RCT2_GLOBAL(0x009AC31C, uint16) = STR_FILE_CONTAINS_INVALID_DATA; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; return 0; } @@ -208,6 +218,9 @@ int scenario_load_and_play_from_path(const char *path) if (!scenario_load(path)) return 0; + strcpy(_scenarioPath, path); + _scenarioFileName = path_get_filename(_scenarioPath); + log_verbose("starting scenario, %s", path); RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; @@ -236,7 +249,7 @@ int scenario_load_and_play_from_path(const char *path) mainWindow->saved_view_y -= mainWindow->viewport->view_height >> 1; window_invalidate(mainWindow); - sub_69E9A7(); + reset_all_sprite_quadrant_placements(); window_new_ride_init_vars(); // Set the scenario pseduo-random seeds @@ -248,7 +261,7 @@ int scenario_load_and_play_from_path(const char *path) if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) & PARK_FLAGS_NO_MONEY_SCENARIO) RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) |= PARK_FLAGS_NO_MONEY; sub_684AC3(); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); + scenery_set_default_placement_configuration(); news_item_init_queue(); if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) != OBJECTIVE_NONE) window_park_objective_open(); @@ -258,43 +271,35 @@ int scenario_load_and_play_from_path(const char *path) RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, money32) = calculate_company_value(); RCT2_GLOBAL(0x013587D0, money32) = RCT2_GLOBAL(0x013573DC, money32) - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(RCT2_GLOBAL(0x013573DC, sint32)); + sub_69E869(); // (loan related) strcpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, s6Info->details); strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s6Info->name); - if (RCT2_GLOBAL(0x009ADAE4, sint32) != -1) { - char *ebp = RCT2_GLOBAL(0x009ADAE4, char*); + rct_stex_entry* stex = g_stexEntries[0]; + if ((int)stex != -1) { + char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; - // - format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, RCT2_GLOBAL(ebp + 2, uint16), 0); - - // Set park name - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_RENAME_PARK; - game_do_command(1, 1, 0, *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 0)), GAME_COMMAND_33, - *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 8)), - *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 4))); - game_do_command(2, 1, 0, *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 12)), GAME_COMMAND_33, - *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 20)), - *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 16))); - game_do_command(0, 1, 0, *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 24)), GAME_COMMAND_33, - *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 32)), - *((int*)(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER + 28))); + // Set localised park name + format_string(buffer, stex->park_name, 0); + park_set_name(buffer); - // - format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, RCT2_GLOBAL(ebp + 0, uint16), 0); - strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, 31); + // Set localised scenario name + format_string(buffer, stex->scenario_name, 0); + strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, buffer, 31); ((char*)RCT2_ADDRESS_SCENARIO_NAME)[31] = '\0'; - // Set scenario details - format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, RCT2_GLOBAL(ebp + 4, uint16), 0); - strncpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, 255); + // Set localised scenario details + format_string(buffer, stex->details, 0); + strncpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, buffer, 255); ((char*)RCT2_ADDRESS_SCENARIO_DETAILS)[255] = '\0'; } // Set the last saved game path + format_string(gScenarioSaveName, RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id), (void*)RCT2_ADDRESS_PARK_NAME_ARGS); strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH); - format_string((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2 + strlen((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2), RCT2_GLOBAL(0x0013573D4, uint16), (void*)0x0013573D8); + strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2 + strlen((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2), gScenarioSaveName); strcat((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, ".SV6"); memset((void*)0x001357848, 0, 56); @@ -302,7 +307,7 @@ int scenario_load_and_play_from_path(const char *path) RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PROFIT, money32) = 0; RCT2_GLOBAL(0x01358334, money32) = 0; RCT2_GLOBAL(0x01358338, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32) = 0x80000000; + RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32) = MONEY32_UNDEFINED; RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_ADMISSIONS, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_INCOME_FROM_ADMISSIONS, uint32) = 0; RCT2_GLOBAL(0x013587D8, uint16) = 63; @@ -312,9 +317,9 @@ int scenario_load_and_play_from_path(const char *path) award_reset(); reset_all_ride_build_dates(); date_reset(); - RCT2_CALLPROC_EBPSAFE(0x00674576); + duck_remove_all(); park_calculate_size(); - RCT2_CALLPROC_EBPSAFE(0x006C1955); + staff_reset_stats(); RCT2_GLOBAL(0x01358840, uint8) = 0; memset((void*)0x001358102, 0, 20); RCT2_GLOBAL(0x00135882E, uint16) = 0; @@ -327,16 +332,14 @@ int scenario_load_and_play_from_path(const char *path) RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_18; - RCT2_CALLPROC_EBPSAFE(0x006837E3); // (palette related) + load_palette(); gfx_invalidate_screen(); RCT2_GLOBAL(0x009DEA66, uint16) = 0; RCT2_GLOBAL(0x009DEA5C, uint16) = 62000; // (doesn't appear to ever be read) - return 1; } - void scenario_end() { rct_window* w; @@ -349,18 +352,26 @@ void scenario_end() window_park_objective_open(); } -/* -* rct2: 0x0066A752 -**/ +void scenario_set_filename(const char *value) +{ + subsitute_path(_scenarioPath, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), value); + _scenarioFileName = path_get_filename(_scenarioPath); +} + +/** + * + * rct2: 0x0066A752 + **/ void scenario_failure() { RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32) = 0x80000001; scenario_end(); } -/* - * rct2: 0x0066A75E - **/ +/** + * + * rct2: 0x0066A75E + */ void scenario_success() { int i; @@ -371,18 +382,19 @@ void scenario_success() peep_applause(); for (i = 0; i < gScenarioListCount; i++) { - char *cur_scenario_name = RCT2_ADDRESS(0x135936C, char); scenario = &gScenarioList[i]; - if (0 == strncmp(cur_scenario_name, scenario->path, 256)){ - if (scenario->flags & SCENARIO_FLAGS_COMPLETED && scenario->company_value < current_val) - break; // not a new high score -> no glory + if (strequals(scenario->path, _scenarioFileName, 256, true)) { + // Check if record company value has been broken + if ((scenario->flags & SCENARIO_FLAGS_COMPLETED) && scenario->company_value >= current_val) + break; + // Allow name entry RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT; scenario->company_value = current_val; scenario->flags |= SCENARIO_FLAGS_COMPLETED; scenario->completed_by[0] = 0; - RCT2_GLOBAL(0x013587C0, uint32) = current_val; // value used in window for score? + RCT2_GLOBAL(0x013587C0, uint32) = current_val; scenario_scores_save(); break; } @@ -391,170 +403,32 @@ void scenario_success() } /** -* Checks if there are 10 rollercoasters of different subtype with -* excitement >= 600 . -* rct2: -**/ -void scenario_objective5_check() + * + * rct2: 0x006695E8 + */ +void scenario_success_submit_name(const char *name) { - int i, rcs = 0; - uint8 type_already_counted[256]; - rct_ride* ride; + int i; + rct_scenario_basic* scenario; + uint32 scenarioWinCompanyValue; + + for (i = 0; i < gScenarioListCount; i++) { + scenario = &gScenarioList[i]; - memset(type_already_counted, 0, 256); - - FOR_ALL_RIDES(i, ride) { - uint8 subtype_id = ride->subtype; - rct_ride_type *rideType = gRideTypeList[subtype_id]; - - if ((rideType->category[0] == RIDE_GROUP_ROLLERCOASTER || rideType->category[1] == RIDE_GROUP_ROLLERCOASTER) && - ride->status == RIDE_STATUS_OPEN && - ride->excitement >= RIDE_RATING(6,00) && type_already_counted[subtype_id] == 0){ - type_already_counted[subtype_id]++; - rcs++; - } - } - - if (rcs >= 10) - scenario_success(); -} - -/** - * Checks if there are 10 rollercoasters of different subtype with - * excitement > 700 and a minimum length; - * rct2: 0x0066A6B5 - **/ -void scenario_objective8_check() -{ - int i, rcs = 0; - uint8 type_already_counted[256]; - rct_ride* ride; - sint16 objective_length = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); - - memset(type_already_counted, 0, 256); - - FOR_ALL_RIDES(i, ride) { - uint8 subtype_id = ride->subtype; - rct_ride_type *rideType = gRideTypeList[subtype_id]; - if ((rideType->category[0] == RIDE_GROUP_ROLLERCOASTER || rideType->category[1] == RIDE_GROUP_ROLLERCOASTER) && - ride->status == RIDE_STATUS_OPEN && - ride->excitement >= RIDE_RATING(7,00) && type_already_counted[subtype_id] == 0){ - - if ((ride_get_total_length(ride) >> 16) > objective_length) { - type_already_counted[subtype_id]++; - rcs++; + if (strequals(scenario->path, _scenarioFileName, 256, true)) { + scenarioWinCompanyValue = RCT2_GLOBAL(0x013587C0, uint32); + if (scenario->company_value == scenarioWinCompanyValue) { + strncpy(scenario->completed_by, name, 64); + strncpy((char*)0x013587D8, name, 32); + scenario_scores_save(); } + break; } } - - if (rcs >= 10) - scenario_success(); + + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT; } - - -/* - * Checks the win/lose conditions of the current objective. - * rct2: 0x0066A4B2 - **/ -void scenario_objectives_check() -{ - uint8 objective_type = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8), - objective_year = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8); - sint16 park_rating = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16), - guests_in_park = RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16), - objective_guests = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16), - cur_month_year = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16); - uint32 scenario_completed_company_value = RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32); - sint32 objective_currency = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, sint32), - park_value = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, sint32); - - - if ( scenario_completed_company_value != 0x80000000) - return; - - switch (objective_type) { - case OBJECTIVE_GUESTS_BY://1 - - if (cur_month_year == 8 * objective_year){ - if (park_rating >= 600 && guests_in_park >= objective_guests) - scenario_success(); - else - scenario_failure(); - } - break; - - case OBJECTIVE_PARK_VALUE_BY://2 - - if (cur_month_year == 8 * objective_year) { - if (park_value >= objective_currency) - scenario_success(); - else - scenario_failure(); - } - break; - - case OBJECTIVE_10_ROLLERCOASTERS://5 - - scenario_objective5_check(); - break; - - case OBJECTIVE_GUESTS_AND_RATING://6 - - if (park_rating >= 700 && guests_in_park >= objective_guests) - scenario_success(); - break; - - case OBJECTIVE_MONTHLY_RIDE_INCOME://7 - { - sint32 monthly_ride_income = RCT2_GLOBAL(RCT2_ADDRESS_MONTHLY_RIDE_INCOME, sint32); - if (monthly_ride_income >= objective_currency) - scenario_success(); - break; - } - case OBJECTIVE_10_ROLLERCOASTERS_LENGTH://8 - - scenario_objective8_check(); - break; - - case OBJECTIVE_FINISH_5_ROLLERCOASTERS://9 - { - int i; - rct_ride* ride; - - // ORIGINAL BUG?: - // This does not check if the rides are even rollercoasters nevermind the right rollercoasters to be finished. - // It also did not exclude null rides. - int rcs = 0; - FOR_ALL_RIDES(i, ride) - if (ride->status != RIDE_STATUS_CLOSED && ride->excitement >= objective_currency) - rcs++; - - if (rcs >= 5) - scenario_success(); - break; - } - case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE://A - { - sint32 current_loan = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, sint32); - if (current_loan <= 0 && park_value >= objective_currency) - scenario_success(); - break; - } - case OBJECTIVE_MONTHLY_FOOD_INCOME://B - { - sint32 income_sum = RCT2_GLOBAL(0x013578A4, sint32) + RCT2_GLOBAL(0x013578A0, sint32) + - RCT2_GLOBAL(0x0135789C, sint32) + RCT2_GLOBAL(0x01357898, sint32); - if (income_sum >= objective_currency) - scenario_success(); - break; - } - default: - return; - } -} - - /* * Send a warning when entrance price is too high. * rct2: 0x0066A80E @@ -578,91 +452,186 @@ void scenario_entrance_fee_too_high_check() } } +static void scenario_autosave_check() +{ + uint32 next_month_tick = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) + 4; + uint16 month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); + bool shouldSave = 0; + + switch (gConfigGeneral.autosave_frequency) { + case AUTOSAVE_EVERY_WEEK: + shouldSave = (next_month_tick % 0x4000 == 0); + break; + case AUTOSAVE_EVERY_2_WEEKS: + shouldSave = (next_month_tick % 0x8000 == 0); + break; + case AUTOSAVE_EVERY_MONTH: + shouldSave = (next_month_tick >= 0x10000); + break; + case AUTOSAVE_EVERY_4_MONTHS: + if (next_month_tick >= 0x10000) + shouldSave = (((month + 1) & 3) == 0); + break; + case AUTOSAVE_EVERY_YEAR: + if (next_month_tick >= 0x10000) + shouldSave = (((month + 1) & 7) == 0); + break; + } + + if (shouldSave) + game_autosave(); +} + +static void scenario_day_update() +{ + finance_update_daily_profit(); + peep_update_days_in_queue(); + get_local_time(); + switch (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8)) { + case OBJECTIVE_10_ROLLERCOASTERS: + case OBJECTIVE_GUESTS_AND_RATING: + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + scenario_objective_check(); + break; + } + + uint16 unk = (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? 40 : 7; + RCT2_GLOBAL(0x00135882E, uint16) = RCT2_GLOBAL(0x00135882E, uint16) > unk ? RCT2_GLOBAL(0x00135882E, uint16) - unk : 0; + + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint32) |= BTM_TB_DIRTY_FLAG_DATE; +} + +static void scenario_week_update() +{ + int month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7; + + finance_pay_wages(); + finance_pay_research(); + finance_pay_interest(); + marketing_update(); + peep_problem_warnings_update(); + ride_check_all_reachable(); + ride_update_favourited_stat(); + + rct_water_type* water_type = (rct_water_type*)object_entry_groups[OBJECT_TYPE_WATER].chunks[0]; + + if (month <= MONTH_APRIL && (sint32)water_type != -1 && water_type->var_0E & 1) { + // 100 attempts at finding some water to create a few ducks at + for (int i = 0; i < 100; i++) { + if (scenario_create_ducks()) + break; + } + } + park_update_histories(); + park_calculate_size(); +} + +static void scenario_fortnight_update() +{ + finance_pay_ride_upkeep(); +} + +static void scenario_month_update() +{ + finance_shift_expenditure_table(); + scenario_objective_check(); + scenario_entrance_fee_too_high_check(); + award_update_all(); +} + /* * Scenario and finance related update iteration. * rct2: 0x006C44B1 **/ void scenario_update() { - uint8 screen_flags = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8); - uint32 month_tick = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16), - next_month_tick = month_tick + 4; - uint8 month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7, - current_days_in_month = (uint8)days_in_month[month], - objective_type = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8); - - if (screen_flags & (~SCREEN_FLAGS_PLAYING)) // only in normal play mode + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & ~SCREEN_FLAGS_PLAYING) return; - if ((current_days_in_month * next_month_tick) >> 16 != (current_days_in_month * month_tick) >> 16) { - // daily checks - finance_update_daily_profit(); // daily profit update - RCT2_CALLPROC_EBPSAFE(0x0069C35E); // some kind of peeps days_visited update loop - get_local_time(); - RCT2_CALLPROC_EBPSAFE(0x0066A13C); // objective 6 dragging - if (objective_type == 10 || objective_type == 9 || objective_type == 8 || - objective_type == 6 || objective_type == 5) { - scenario_objectives_check(); - } + uint32 currentMonthTick = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16); + uint32 nextMonthTick = currentMonthTick + 4; + uint8 currentMonth = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7; + uint8 currentDaysInMonth = (uint8)days_in_month[currentMonth]; - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + scenario_autosave_check(); + if ((currentDaysInMonth * nextMonthTick) >> 16 != (currentDaysInMonth * currentMonthTick) >> 16) { + scenario_day_update(); + } + if (nextMonthTick % 0x4000 == 0) { + scenario_week_update(); + } + if (nextMonthTick % 0x8000 == 0) { + scenario_fortnight_update(); } - - //if ( (unsigned int)((4 * current_day) & 0xFFFF) >= 0xFFEFu) { - if ( next_month_tick % 0x4000 == 0) { - // weekly checks - finance_pay_wages(); - finance_pay_research(); - finance_pay_interest(); - marketing_update(); - peep_problem_warnings_update(); - ride_check_all_reachable(); - ride_update_favourited_stat(); - - if (month <= 1 && RCT2_GLOBAL(0x009ADAE0, sint32) != -1 && RCT2_GLOBAL(0x009ADAE0 + 14, uint16) & 1) { - for (int i = 0; i < 100; ++i) { - int carry; - RCT2_CALLPROC_EBPSAFE(0x006744A9); // clears carry flag on failure -.- - #ifdef _MSC_VER - __asm mov carry, 0; - __asm adc carry, 0; - #else - __asm__ ( "mov %[carry], 0; " : [carry] "+m" (carry) ); - __asm__ ( "adc %[carry], 0; " : [carry] "+m" (carry) ); - #endif - - if (!carry) - break; - } - } - park_update_histories(); - park_calculate_size(); - } - - //if ( (unsigned int)((2 * current_day) & 0xFFFF) >= 0xFFF8) { - if (next_month_tick % 0x8000 == 0) { - // fortnightly - finance_pay_ride_upkeep(); - } - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) = (uint16)next_month_tick; - if (next_month_tick >= 0x10000) { - // month ends actions + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) = (uint16)nextMonthTick; + if (nextMonthTick >= 0x10000) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16)++; - RCT2_GLOBAL(0x009A9804, uint32) |= 2; - RCT2_CALLPROC_EBPSAFE(0x0069DEAD); - scenario_objectives_check(); - scenario_entrance_fee_too_high_check(); - award_update_all(); + scenario_month_update(); } - } /** -* -* rct2: 0x006E37D2 -*/ + * + * rct2: 0x006744A9 + */ +static int scenario_create_ducks() +{ + int i, j, r, c, x, y, waterZ, centreWaterZ, x2, y2; + + r = scenario_rand(); + x = ((r >> 16) & 0xFFFF) & 0x7F; + y = (r & 0xFFFF) & 0x7F; + x = (x + 64) * 32; + y = (y + 64) * 32; + + if (!map_is_location_in_park(x, y)) + return 0; + + centreWaterZ = (map_element_height(x, y) >> 16) & 0xFFFF; + if (centreWaterZ == 0) + return 0; + + // Check 7x7 area around centre tile + x2 = x - (32 * 3); + y2 = y - (32 * 3); + c = 0; + for (i = 0; i < 7; i++) { + for (j = 0; j < 7; j++) { + waterZ = (map_element_height(x2, y2) >> 16) & 0xFFFF; + if (waterZ == centreWaterZ) + c++; + + x2 += 32; + } + x2 -= 224; + y2 += 32; + } + + // Must be at least 25 water tiles of the same height in 7x7 area + if (c < 25) + return 0; + + // Set x, y to the centre of the tile + x += 16; + y += 16; + c = (scenario_rand() & 3) + 2; + for (i = 0; i < c; i++) { + r = scenario_rand(); + x2 = (r >> 16) & 0x7F; + y2 = (r & 0xFFFF) & 0x7F; + create_duck(x + x2 - 64, y + y2 - 64); + } + + return 1; +} + +/** + * + * rct2: 0x006E37D2 + */ unsigned int scenario_rand() { int eax = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32); @@ -676,26 +645,22 @@ unsigned int scenario_rand() */ void scenario_prepare_rides_for_save() { - int i, x, y; - rct_map_element *mapElement; + int i; rct_ride *ride; + map_element_iterator it; int isFiveCoasterObjective = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_FINISH_5_ROLLERCOASTERS; // Set all existing track to be indestructible - for (y = 0; y < 256; y++) { - for (x = 0; x < 256; x++) { - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); - do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_TRACK) { - if (isFiveCoasterObjective) - mapElement->flags |= 0x40; - else - mapElement->flags &= ~0x40; - } - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + map_element_iterator_begin(&it); + do { + if (map_element_get_type(it.element) == MAP_ELEMENT_TYPE_TRACK) { + if (isFiveCoasterObjective) + it.element->flags |= 0x40; + else + it.element->flags &= ~0x40; } - } + } while (map_element_iterator_next(&it)); // Set all existing rides to have indestructible track FOR_ALL_RIDES(i, ride) { @@ -717,20 +682,21 @@ int scenario_prepare_for_save() s6Info->entry.flags = 255; - char *stex = RCT2_GLOBAL(0x009ADAE4, char*); - if (stex != (char*)0xFFFFFFFF) { - format_string(buffer, RCT2_GLOBAL(stex, uint16), NULL); + rct_stex_entry* stex = g_stexEntries[0]; + if ((int)stex != 0xFFFFFFFF) { + format_string(buffer, stex->scenario_name, NULL); strncpy(s6Info->name, buffer, sizeof(s6Info->name)); - s6Info->entry = *((rct_object_entry*)0x00F4287C); + + memcpy(&s6Info->entry, &object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0], sizeof(rct_object_entry)); } if (s6Info->name[0] == 0) - format_string(s6Info->name, RCT2_GLOBAL(0x013573D4, rct_string_id), (void*)0x013573D8); + format_string(s6Info->name, RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id), (void*)RCT2_ADDRESS_PARK_NAME_ARGS); s6Info->objective_type = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8); s6Info->objective_arg_1 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8); - s6Info->objective_arg_2 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, uint8); - s6Info->objective_arg_3 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint8); + s6Info->objective_arg_2 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, sint32); + s6Info->objective_arg_3 = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); scenario_prepare_rides_for_save(); @@ -771,7 +737,7 @@ int scenario_write_packed_objects(FILE *file) if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 0xFFFFFFFF || (entry->flags & 0xF0)) continue; - if (!sub_6A9F42(file, (rct_object_entry*)entry)) + if (!write_object_file(file, (rct_object_entry*)entry)) return 0; } @@ -819,6 +785,76 @@ int scenario_write_available_objects(FILE *file) // Free buffers free(dstBuffer); free(buffer); + return 1; +} + +static void sub_677552() +{ + RCT2_GLOBAL(0x0013587BC, uint32) = 0x31144; + 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]); + strncpy(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. + */ +static scenario_fix_ghosts(rct_s6_data *s6) +{ + // Remove all ghost elements + size_t mapElementTotalSize = MAX_MAP_ELEMENTS * sizeof(rct_map_element); + rct_map_element *destinationElement = s6->map_elements; + + for (int y = 0; y < 256; y++) { + for (int x = 0; x < 256; x++) { + rct_map_element *originalElement = map_get_first_element_at(x, y); + do { + if (originalElement->flags & MAP_ELEMENT_FLAG_GHOST) { + int bannerIndex = map_element_get_banner_index(originalElement); + if (bannerIndex != -1) { + rct_banner *banner = &s6->banners[bannerIndex]; + if (banner->type != BANNER_NULL) { + banner->type = BANNER_NULL; + if (is_user_string_id(banner->string_idx)) + s6->custom_strings[(banner->string_idx % MAX_USER_STRINGS) * USER_STRING_MAX_LENGTH] = 0; + } + } + } else { + *destinationElement++ = *originalElement; + } + } while (!map_element_is_last_for_tile(originalElement++)); + + // Set last element flag in case the original last element was never added + (destinationElement - 1)->flags |= MAP_ELEMENT_FLAG_LAST_TILE; + } + } + + // Remove trackless rides + bool rideHasTrack[MAX_RIDES]; + ride_all_has_any_track_elements(rideHasTrack); + for (int i = 0; i < MAX_RIDES; i++) { + rct_ride *ride = &s6->rides[i]; + + if (rideHasTrack[i] || ride->type == RIDE_TYPE_NULL) + continue; + + ride->type = RIDE_TYPE_NULL; + if (is_user_string_id(ride->name)) + s6->custom_strings[(ride->name % MAX_USER_STRINGS) * USER_STRING_MAX_LENGTH] = 0; + } } /** @@ -828,20 +864,15 @@ int scenario_write_available_objects(FILE *file) */ int scenario_save(char *path, int flags) { - rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - - FILE *file; - char *buffer; - sawyercoding_chunk_header chunkHeader; - int encodedLength; - long fileSize; - uint32 checksum; - rct_window *w; rct_viewport *viewport; int viewX, viewY, viewZoom, viewRotation; + if (strcmp(path_get_filename(path), "autosave.sv6")) { + strcpy(gScenarioSaveName, path_get_filename(path)); + path_remove_extension(gScenarioSaveName); + } + if (flags & 2) log_verbose("saving scenario, %s", path); else @@ -851,11 +882,11 @@ int scenario_save(char *path, int flags) if (!(flags & 0x80000000)) window_close_construction_windows(); - RCT2_CALLPROC_EBPSAFE(0x0068B111); - RCT2_CALLPROC_EBPSAFE(0x0069EBE4); - RCT2_CALLPROC_EBPSAFE(0x0069EBA4); - RCT2_CALLPROC_EBPSAFE(0x00677552); - RCT2_CALLPROC_EBPSAFE(0x00674BCF); + map_reorganise_elements(); + reset_0x69EBE4(); + sprite_clear_all_unused(); + sub_677552(); + sub_674BCF(); // Set saved view w = window_get_main(); @@ -877,117 +908,159 @@ int scenario_save(char *path, int flags) RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16) = viewY; RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) = viewZoom | (viewRotation << 8); - // - memset(s6Header, 0, sizeof(rct_s6_header)); - s6Header->type = flags & 2 ? S6_TYPE_SCENARIO : S6_TYPE_SAVEDGAME; - s6Header->num_packed_objects = flags & 1 ? scenario_get_num_packed_objects_to_write() : 0; - s6Header->version = S6_RCT2_VERSION; - s6Header->magic_number = S6_MAGIC_NUMBER; + // 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 < 721; i++) { + uint32 chunkPtr = RCT2_ADDRESS(0x009ACFA4, uint32)[i]; + rct_object_entry_extended *entry = &(RCT2_ADDRESS(0x00F3F03C, rct_object_entry_extended)[i]); + + if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 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); + + scenario_fix_ghosts(s6); + scenario_save_s6(path, s6); + + free(s6); + + if (!(flags & 0x80000000)) + reset_loaded_objects(); + + gfx_invalidate_screen(); + RCT2_GLOBAL(0x009DEA66, uint16) = 0; + return 1; +} + +bool scenario_save_s6(char *path, rct_s6_data *s6) +{ + FILE *file; + char *buffer; + sawyercoding_chunk_header chunkHeader; + int encodedLength; + long fileSize; + uint32 checksum; file = fopen(path, "wb+"); if (file == NULL) { log_error("Unable to write to %s", path); - return 0; + return false; } buffer = malloc(0x600000); if (buffer == NULL) { log_error("Unable to allocate enough space for a write buffer."); fclose(file); - return 0; + return false; } - // Write header chunk + // 0: Write header chunk chunkHeader.encoding = CHUNK_ENCODING_ROTATE; chunkHeader.length = sizeof(rct_s6_header); - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6Header, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->header, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write scenario info chunk - if (flags & 2) { + // 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*)s6Info, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->info, chunkHeader); fwrite(buffer, encodedLength, 1, file); } - // Write packed objects - if (s6Header->num_packed_objects > 0) { + // 2: Write packed objects + if (s6->header.num_packed_objects > 0) { if (!scenario_write_packed_objects(file)) { free(buffer); fclose(file); - return 0; + return false; } } - // Write available objects chunk - scenario_write_available_objects(file); + // 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); + fwrite(buffer, encodedLength, 1, file); - // Write date etc. chunk + // 4: Misc fields (data, rand...) chunk chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 16; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x00F663A8, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->elapsed_months, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write map elements + // 5: Map elements + sprites and other fields chunk chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; - chunkHeader.length = 0x4A85EC; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x00F663B8, chunkHeader); + chunkHeader.length = 0x180000; + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->map_elements, chunkHeader); fwrite(buffer, encodedLength, 1, file); - if (flags & 2) { - // Write chunk + if (s6->header.type == S6_TYPE_SCENARIO) { + // 6: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x27104C; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x010E63B8, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write chunk + // 7: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 4; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x01357844, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->guests_in_park, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write chunk + // 8: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 8; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x01357BC8, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->last_guests_in_park, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write chunk + // 9: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 2; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x01357CB0, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_rating, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write chunk + // 10: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 1082; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x01357CF2, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->active_research_types, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write chunk + // 11: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 16; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x0135832C, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->current_expenditure, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write chunk + // 12: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 4; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x0135853C, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_value, chunkHeader); fwrite(buffer, encodedLength, 1, file); - // Write chunk + // 13: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x761E8; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x01358740, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->completed_company_value, chunkHeader); fwrite(buffer, encodedLength, 1, file); } else { - // Write chunk + // 6: Everything else... chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x2E8570; - encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)0x010E63B8, chunkHeader); + encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader); fwrite(buffer, encodedLength, 1, file); } @@ -1007,35 +1080,230 @@ int scenario_save(char *path, int flags) fseek(file, fileSize, SEEK_SET); fwrite(&checksum, sizeof(uint32), 1, file); fclose(file); - - if (!(flags & 0x80000000)) - RCT2_CALLPROC_EBPSAFE(0x006A9FC0); - - gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, uint16) = 0; - return 1; + return true; } -void scenario_success_submit_name(const char *name) +static void scenario_objective_check_guests_by() { - int i; - rct_scenario_basic* scenario; - uint32 scenarioWinCompanyValue; - - for (i = 0; i < gScenarioListCount; i++) { - char *cur_scenario_name = RCT2_ADDRESS(0x135936C, char); - scenario = &gScenarioList[i]; + uint8 objectiveYear = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8); + sint16 parkRating = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16); + sint16 guestsInPark = RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16); + sint16 objectiveGuests = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); + sint16 currentMonthYear = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16); - if (strncmp(cur_scenario_name, scenario->path, 256) == 0) { - scenarioWinCompanyValue = RCT2_GLOBAL(0x013587C0, uint32); - if (scenario->company_value == scenarioWinCompanyValue) { - strncpy(scenario->completed_by, name, 64); - strncpy((char*)0x013587D8, name, 32); - scenario_scores_save(); - } - break; + if (currentMonthYear == 8 * objectiveYear){ + if (parkRating >= 600 && guestsInPark >= objectiveGuests) + scenario_success(); + else + scenario_failure(); + } +} + +static void scenario_objective_check_park_value_by() +{ + uint8 objectiveYear = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8); + sint16 currentMonthYear = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16); + money32 objectiveParkValue = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32); + money32 parkValue = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32); + + if (currentMonthYear == 8 * objectiveYear) { + if (parkValue >= objectiveParkValue) + scenario_success(); + else + scenario_failure(); + } +} + +/** +* Checks if there are 10 rollercoasters of different subtype with +* excitement >= 600 . +* rct2: +**/ +static void scenario_objective_check_10_rollercoasters() +{ + int i, rcs = 0; + uint8 type_already_counted[256]; + rct_ride* ride; + + memset(type_already_counted, 0, 256); + + FOR_ALL_RIDES(i, ride) { + uint8 subtype_id = ride->subtype; + rct_ride_type *rideType = gRideTypeList[subtype_id]; + + if ((rideType->category[0] == RIDE_GROUP_ROLLERCOASTER || rideType->category[1] == RIDE_GROUP_ROLLERCOASTER) && + ride->status == RIDE_STATUS_OPEN && + ride->excitement >= RIDE_RATING(6,00) && type_already_counted[subtype_id] == 0){ + type_already_counted[subtype_id]++; + rcs++; } } - - RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT; + + if (rcs >= 10) + scenario_success(); } + +/** + * + * rct2: 0x0066A13C + */ +static void scenario_objective_check_guests_and_rating() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) < 700 && RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) >= 1) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_RATING_WARNING_DAYS, uint16)++; + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_RATING_WARNING_DAYS, uint16) == 1) { + news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_4_WEEKS_REMAINING, 0); + } else if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_RATING_WARNING_DAYS, uint16) == 8) { + news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_3_WEEKS_REMAINING, 0); + } else if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_RATING_WARNING_DAYS, uint16) == 15) { + news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_2_WEEKS_REMAINING, 0); + } else if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_RATING_WARNING_DAYS, uint16) == 22) { + news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_RATING_WARNING_1_WEEK_REMAINING, 0); + } else if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_RATING_WARNING_DAYS, uint16) == 29) { + news_item_add_to_queue(NEWS_ITEM_GRAPH, STR_PARK_HAS_BEEN_CLOSED_DOWN, 0); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_PARK_OPEN; + scenario_failure(); + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) = 50; + } + } else if (RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, money32) != 0x80000001) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_RATING_WARNING_DAYS, uint16) = 0; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, money32) != MONEY32_UNDEFINED) + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) >= 700) + if (RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16) >= RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16)) + scenario_success(); +} + +static void scenario_objective_check_monthly_ride_income() +{ + money32 objectiveMonthlyRideIncome = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32); + money32 monthlyRideIncome = RCT2_GLOBAL(RCT2_ADDRESS_MONTHLY_RIDE_INCOME, money32); + if (monthlyRideIncome >= objectiveMonthlyRideIncome) + scenario_success(); +} + +/** + * Checks if there are 10 rollercoasters of different subtype with + * excitement > 700 and a minimum length; + * rct2: 0x0066A6B5 + **/ +static void scenario_objective_check_10_rollercoasters_length() +{ + int i, rcs = 0; + uint8 type_already_counted[256]; + sint16 objective_length = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); + rct_ride* ride; + + memset(type_already_counted, 0, 256); + + FOR_ALL_RIDES(i, ride) { + uint8 subtype_id = ride->subtype; + rct_ride_type *rideType = gRideTypeList[subtype_id]; + if ((rideType->category[0] == RIDE_GROUP_ROLLERCOASTER || rideType->category[1] == RIDE_GROUP_ROLLERCOASTER) && + ride->status == RIDE_STATUS_OPEN && + ride->excitement >= RIDE_RATING(7,00) && type_already_counted[subtype_id] == 0){ + + if ((ride_get_total_length(ride) >> 16) > objective_length) { + type_already_counted[subtype_id]++; + rcs++; + } + } + } + + if (rcs >= 10) + scenario_success(); +} + +static void scenario_objective_check_finish_5_rollercoasters() +{ + int i; + rct_ride* ride; + + money32 objectiveRideExcitement = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32); + + // ORIGINAL BUG?: + // This does not check if the rides are even rollercoasters nevermind the right rollercoasters to be finished. + // It also did not exclude null rides. + int rcs = 0; + FOR_ALL_RIDES(i, ride) + if (ride->status != RIDE_STATUS_CLOSED && ride->excitement >= objectiveRideExcitement) + rcs++; + + if (rcs >= 5) + scenario_success(); +} + +static void scenario_objective_check_replay_loan_and_park_value() +{ + money32 objectiveParkValue = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32); + money32 parkValue = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32); + money32 currentLoan = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32); + + if (currentLoan <= 0 && parkValue >= objectiveParkValue) + scenario_success(); +} + +static void scenario_objective_check_monthly_food_income() +{ + money32 objectiveMonthlyIncome = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32); + sint32 monthlyIncome = + RCT2_GLOBAL(0x013578A4, money32) + + RCT2_GLOBAL(0x013578A0, money32) + + RCT2_GLOBAL(0x0135789C, money32) + + RCT2_GLOBAL(0x01357898, money32); + + if (monthlyIncome >= objectiveMonthlyIncome) + scenario_success(); +} + +/* + * Checks the win/lose conditions of the current objective. + * rct2: 0x0066A4B2 + **/ +static void scenario_objective_check() +{ + uint8 objective_type = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8), + objective_year = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8); + sint16 park_rating = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16), + guests_in_park = RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16), + objective_guests = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16), + cur_month_year = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16); + uint32 scenario_completed_company_value = RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32); + sint32 objective_currency = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, sint32), + park_value = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, sint32); + + + if (scenario_completed_company_value != MONEY32_UNDEFINED) + return; + + switch (objective_type) { + case OBJECTIVE_GUESTS_BY: + scenario_objective_check_guests_by(); + break; + case OBJECTIVE_PARK_VALUE_BY: + scenario_objective_check_park_value_by(); + break; + case OBJECTIVE_10_ROLLERCOASTERS: + scenario_objective_check_10_rollercoasters(); + break; + case OBJECTIVE_GUESTS_AND_RATING: + scenario_objective_check_guests_and_rating(); + break; + case OBJECTIVE_MONTHLY_RIDE_INCOME: + scenario_objective_check_monthly_ride_income(); + break; + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + scenario_objective_check_10_rollercoasters_length(); + break; + case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + scenario_objective_check_finish_5_rollercoasters(); + break; + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + scenario_objective_check_replay_loan_and_park_value(); + break; + case OBJECTIVE_MONTHLY_FOOD_INCOME: + scenario_objective_check_monthly_food_income(); + break; + } +} \ No newline at end of file diff --git a/src/scenario.h b/src/scenario.h index 5751dcd563..b9adcdf8ee 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -21,8 +21,16 @@ #ifndef _SCENARIO_H_ #define _SCENARIO_H_ -#include "rct2.h" +#include "common.h" +#include "management/award.h" +#include "management/news_item.h" +#include "management/research.h" +#include "ride/ride.h" #include "object.h" +#include "platform/platform.h" +#include "world/banner.h" +#include "world/map.h" +#include "world/sprite.h" /** * SV6/SC6 header chunk @@ -83,7 +91,16 @@ typedef struct { char completed_by[64]; // 0x0270 } rct_scenario_basic; -/* This will be useful for backwards compatibility +typedef struct { + rct_string_id scenario_name; // 0x00 + rct_string_id park_name; // 0x02 + rct_string_id details; // 0x04 + uint8 var_06; +} rct_stex_entry; + +#define g_stexEntries ((rct_stex_entry**)object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].chunks) + +// This will be useful for backwards compatibility typedef struct { // SC6[0] rct_s6_header header; @@ -121,21 +138,21 @@ typedef struct { uint16 word_013573CE; uint16 word_013573D0; uint8 pad_013573D2[2]; - uint16 word_013573D4; - uint8 pad_013573D6[4]; - uint32 dword_013573D8; - uint32 dword_013573DC; + rct_string_id park_name; + uint8 pad_013573D6[2]; + uint32 park_name_args; + money32 initial_cash; money32 current_loan; uint32 park_flags; money16 park_entrance_fee; uint16 word_013573EA; uint16 word_013573EC; - uint8 pad_013573EE[16]; + uint8 pad_013573EE[2]; uint8 byte_013573F0; - uint8 pad_013573F1[2]; + uint8 pad_013573F1; rct2_peep_spawn peep_spawns[2]; uint8 guest_count_change_modifier; - uint8 byte_013573FF; + uint8 current_research_level; uint8 pad_01357400[4]; uint32 dword_01357404; uint32 dword_01357408; @@ -180,22 +197,22 @@ typedef struct { uint8 research_progress_stage; uint32 dword_01357CF4; uint8 byte_01357CF8[1000]; - uint32 dword_013580E0; + uint32 next_research_item; uint16 research_progress; uint8 next_research_category; uint8 next_research_expected_day; uint8 next_research_expected_month; - uint8 byte_013580E9; + uint8 guest_initial_happiness; uint16 park_size; uint16 guest_generation_probability; uint16 total_ride_value; - uint32 dword_013580F0; - uint16 dword_013580F4; - uint8 dword_013580F6; - uint8 dword_013580F7; + money32 maximum_loan; + money16 guest_initial_cash; + uint8 guest_initial_hunger; + uint8 guest_initial_thirst; uint8 objective_type; uint8 objective_year; - uint8 pad_013580FA[4]; + uint8 pad_013580FA[2]; money32 objective_currency; uint16 objective_guests; uint8 campaign_weeks_left[20]; @@ -212,71 +229,62 @@ typedef struct { uint8 pad_0135833A[2]; // Ignored in scenario - uint8 pad_0135833C[2]; - money32 park_value; - money32 park_value_history[128]; + money32 weekly_profit_history[128]; // SC6[12] + money32 park_value; + + // Ignored in scenario + money32 park_value_history[128]; + + // SC6[13] money32 completed_company_value; uint32 total_admissions; money32 income_from_admissions; money32 company_value; uint8 byte_01358750[16]; rct_award awards[4]; - uint16 word_01358770; - uint16 word_01358772; + money16 land_price; + money16 construction_rights_price; uint16 word_01358774; - uint8 pad_01358776[4]; + uint8 pad_01358776[2]; uint32 dword_01358778[17]; uint32 dword_013587BC; uint32 dword_013587C0; uint32 dword_013587C4; uint16 dword_013587C8; - uint8 pad_013587CA[16]; + uint8 pad_013587CA[6]; uint32 dword_013587D0; - uint8 pad_013587D4[8]; - uint16 word_013587D8[16]; + uint8 pad_013587D4[4]; + char scenario_completed_name[32]; money32 cash; uint8 pad_013587FC[50]; uint16 word_0135882E; - uint16 word_01358830; - uint16 word_01358832; + uint16 map_size_units; + uint16 map_size_minus_2; uint16 map_size; - uint16 word_01358836; + uint16 map_max_xy; uint32 word_01358838; uint16 suggested_max_guests; - uint16 word_0135883E; + uint16 park_rating_warning_days; uint8 word_01358840; - uint8 word_01358841; - uint8 pad_01358842[4]; - uint32 dword_01358844; - uint8 pad_01358848; - uint32 dword_01358849; - uint8 pad_0135884D[2]; - uint8 dword_0135884E[622]; - uint8 pad_01359206[2]; + uint8 rct1_water_colour; + uint8 pad_01358842[2]; + rct_research_item research_items[500]; uint16 word_01359208; char scenario_name[64]; char scenario_description[255]; uint8 byte_01359349; - uint8 byte_0135934A; - uint8 pad_0135934B[3]; + uint8 current_interest_rate; + uint8 pad_0135934B; uint32 dword_0135934C; uint16 park_entrance_x[4]; uint16 park_entrance_y[4]; uint16 park_entrance_z[4]; - uint8 byte_01359368; - uint8 pad_01359369[3]; - uint8 byte_0135936C[256]; - uint8 byte_0135946C[3256]; - uint8 byte_0135A124; - uint8 byte_0135A125; - uint16 word_0135A126; - uint8 byte_0135A128; - uint8 byte_0135A129; - uint8 byte_0135A12A; - uint8 byte_0135A12B[793]; - uint8 byte_0135A444[1200]; + uint8 park_entrance_direction[4]; + uint8 scenario_filename[256]; + uint8 saved_expansion_pack_names[3256]; + rct_banner banners[250]; char custom_strings[0x8000]; uint32 game_ticks_1; rct_ride rides[255]; @@ -284,18 +292,18 @@ typedef struct { uint16 saved_view_x; uint16 saved_view_y; uint16 saved_view_zoom_and_rotation; - uint8 byte_013886A0[6000]; + uint8 map_animations[6000]; uint8 byte_01389E10[6000]; - uint16 word_0138B580; - uint8 pad_0138B580[2]; + uint16 num_map_animations; + uint8 pad_0138B582[2]; uint16 word_0138B584; uint16 word_0138B586; uint16 word_0138B588; uint16 word_0138B58A; uint16 word_0138B58C; uint16 word_0138B58E; - uint8 byte_0138B590; - uint8 byte_0138B591; + uint8 ride_ratings_current_ride; + uint8 ride_ratings_state; uint8 byte_0138B592; uint8 byte_0138B593; uint16 word_0138B594; @@ -329,17 +337,17 @@ typedef struct { uint16 word_0138B5CC; uint16 word_0138B5CE[31]; uint8 ride_measurements[0x25860]; - uint32 dword_13B0E6C; - uint16 word_13B0E70; - uint32 dword_13B0E72[0x6600]; // 512 bytes per staff peep + 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 unk_13CA73E; - uint8 pad_13CA73E; + uint8 pad_13CA73F; uint8 byte_13CA740; uint8 byte_13CA741; - uint8 byte_13CA7424[4]; + uint8 byte_13CA742[4]; uint8 climate; uint8 pad_013CA747; uint16 climate_update_timer; @@ -357,9 +365,9 @@ typedef struct { uint8 byte_13CE730[64]; uint32 dword_13CE770; uint16 word_13CE774; - uint16 word_13CE776[217]; + uint16 word_13CE776; + uint8 pad_13CE778[434]; } rct_s6_data; -*/ enum { SCENARIO_FLAGS_VISIBLE = (1 << 0), @@ -403,8 +411,11 @@ extern int gScenarioListCount; extern int gScenarioListCapacity; extern rct_scenario_basic *gScenarioList; +extern char gScenarioSaveName[MAX_PATH]; + int scenario_scores_save(); void scenario_load_list(); +rct_scenario_basic *get_scenario_by_filename(const char *filename); int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info); int scenario_load(const char *path); int scenario_load_and_play(const rct_scenario_basic *scenario); @@ -413,6 +424,10 @@ void scenario_update(); unsigned int scenario_rand(); int scenario_prepare_for_save(); int scenario_save(char *path, int flags); +bool scenario_save_s6(char *path, rct_s6_data *s6); +void scenario_set_filename(const char *value); +void scenario_failure(); +void scenario_success(); void scenario_success_submit_name(const char *name); #endif diff --git a/src/scenario_list.c b/src/scenario_list.c index 8b7a26cc5f..b924cbf0a5 100644 --- a/src/scenario_list.c +++ b/src/scenario_list.c @@ -32,7 +32,7 @@ static void scenario_list_sort(); static int scenario_list_sort_compare(const void *a, const void *b); static int scenario_scores_load(); -static rct_scenario_basic *get_scenario_by_filename(const char *filename) +rct_scenario_basic *get_scenario_by_filename(const char *filename) { int i; for (i = 0; i < gScenarioListCount; i++) @@ -143,14 +143,23 @@ static void scenario_list_sort() } /** -* Basic scenario information compare function for sorting. -* rct2: 0x00677C08 -*/ + * Basic scenario information compare function for sorting. + * rct2: 0x00677C08 + */ static int scenario_list_sort_compare(const void *a, const void *b) { return strcmp(((rct_scenario_basic*)a)->name, ((rct_scenario_basic*)b)->name); } +/** + * Gets the path for the scenario scores path. + */ +static void scenario_scores_get_path(char *outPath) +{ + platform_get_user_directory(outPath, NULL); + strcat(outPath, "scores.dat"); +} + /** * * rct2: 0x006775A8 @@ -158,6 +167,9 @@ static int scenario_list_sort_compare(const void *a, const void *b) static int scenario_scores_load() { FILE *file; + char scoresPath[MAX_PATH]; + + scenario_scores_get_path(scoresPath); // Free scenario list if already allocated if (gScenarioList != NULL) { @@ -166,17 +178,22 @@ static int scenario_scores_load() } // Try and load the scores file - file = fopen(get_file_path(PATH_ID_SCORES), "rb"); + + // First check user folder and then fallback to install directory + file = fopen(scoresPath, "rb"); if (file == NULL) { - RCT2_ERROR("Unable to load scenario scores."); - return 0; + file = fopen(get_file_path(PATH_ID_SCORES), "rb"); + if (file == NULL) { + log_error("Unable to load scenario scores."); + return 0; + } } // Load header rct_scenario_scores_header header; if (fread(&header, 16, 1, file) != 1) { fclose(file); - RCT2_ERROR("Invalid header in scenario scores file."); + log_error("Invalid header in scenario scores file."); return 0; } gScenarioListCount = header.scenario_count; @@ -206,10 +223,13 @@ static int scenario_scores_load() int scenario_scores_save() { FILE *file; - - file = fopen(get_file_path(PATH_ID_SCORES), "wb"); + char scoresPath[MAX_PATH]; + + scenario_scores_get_path(scoresPath); + + file = fopen(scoresPath, "wb"); if (file == NULL) { - RCT2_ERROR("Unable to save scenario scores."); + log_error("Unable to save scenario scores."); return 0; } diff --git a/src/sprites.h b/src/sprites.h index 3747e4bdad..b30b07c0a6 100644 --- a/src/sprites.h +++ b/src/sprites.h @@ -188,6 +188,8 @@ enum { SPR_TAB_RIDE_14 = SPR_TAB_RIDE_0 + 14, SPR_TAB_RIDE_15 = SPR_TAB_RIDE_0 + 15, + STR_TAB_PARK = 5466, + SPR_AWARD_MOST_UNTIDY = 5469, SPR_MOST_TIDY = SPR_AWARD_MOST_UNTIDY + 1, SPR_BEST_ROLLERCOASTERS = SPR_AWARD_MOST_UNTIDY + 2, @@ -343,6 +345,41 @@ enum { SPR_INTRO_INFOGRAMES_01 = SPR_INTRO_INFOGRAMES_00 + 2, SPR_INTRO_INFOGRAMES_11 = SPR_INTRO_INFOGRAMES_00 + 3, SPR_CREDITS_INFOGRAMES = 23230, + + SPR_G2_BEGIN = 324288, + SPR_G2_LOGO = SPR_G2_BEGIN + 0, + SPR_G2_TITLE = SPR_G2_BEGIN + 1, + SPR_G2_FASTFORWARD = SPR_G2_BEGIN + 2, + SPR_G2_SPEED_ARROW = SPR_G2_BEGIN + 3, + SPR_G2_HYPER_ARROW = SPR_G2_BEGIN + 4, + SPR_G2_TAB_TWITCH = SPR_G2_BEGIN + 5, + SPR_G2_TAB_LAND = SPR_G2_BEGIN + 6, + + SPR_G2_PLACEHOLDER = SPR_G2_BEGIN + 7, + + SPR_G2_ZOOM_IN = SPR_G2_BEGIN + 8, + SPR_G2_ZOOM_IN_DISABLED = SPR_G2_BEGIN + 9, + SPR_G2_ZOOM_OUT = SPR_G2_BEGIN + 10, + SPR_G2_ZOOM_OUT_DISABLED = SPR_G2_BEGIN + 11, + + SPR_G2_TAB_TREE = SPR_G2_BEGIN + 12, + SPR_G2_TAB_PENCIL = SPR_G2_BEGIN + 13, + SPR_G2_BUTTON_LARGE_SCENERY = SPR_G2_BEGIN + 14, + SPR_G2_BUTTON_TREES = SPR_G2_BEGIN + 15, + SPR_G2_BUTTON_FOOTPATH = SPR_G2_BEGIN + 16, + + SPR_G2_RCT1_CLOSE_BUTTON_0 = SPR_G2_BEGIN + 17, + SPR_G2_RCT1_CLOSE_BUTTON_1 = SPR_G2_BEGIN + 18, + SPR_G2_RCT1_CLOSE_BUTTON_2 = SPR_G2_BEGIN + 19, + SPR_G2_RCT1_CLOSE_BUTTON_3 = SPR_G2_BEGIN + 20, + SPR_G2_RCT1_TEST_BUTTON_0 = SPR_G2_BEGIN + 21, + SPR_G2_RCT1_TEST_BUTTON_1 = SPR_G2_BEGIN + 22, + SPR_G2_RCT1_TEST_BUTTON_2 = SPR_G2_BEGIN + 23, + SPR_G2_RCT1_TEST_BUTTON_3 = SPR_G2_BEGIN + 24, + SPR_G2_RCT1_OPEN_BUTTON_0 = SPR_G2_BEGIN + 25, + SPR_G2_RCT1_OPEN_BUTTON_1 = SPR_G2_BEGIN + 26, + SPR_G2_RCT1_OPEN_BUTTON_2 = SPR_G2_BEGIN + 27, + SPR_G2_RCT1_OPEN_BUTTON_3 = SPR_G2_BEGIN + 28, }; #endif diff --git a/src/title.c b/src/title.c index 422a7c2b24..ecf2266cbc 100644 --- a/src/title.c +++ b/src/title.c @@ -18,6 +18,7 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "addresses.h" #include "audio/audio.h" #include "config.h" @@ -32,34 +33,40 @@ #include "intro.h" #include "management/news_item.h" #include "management/research.h" +#include "openrct2.h" #include "ride/ride.h" #include "scenario.h" +#include "util/util.h" #include "world/climate.h" #include "world/map.h" #include "world/park.h" +#include "world/scenery.h" #include "world/sprite.h" -static const int gOldMusic = 0; static const int gRandomShowcase = 0; #pragma region Showcase script enum { TITLE_SCRIPT_WAIT, - TITLE_SCRIPT_LOAD, + TITLE_SCRIPT_LOADMM, TITLE_SCRIPT_LOCATION, TITLE_SCRIPT_ROTATE, + TITLE_SCRIPT_ZOOM, TITLE_SCRIPT_RESTART, + TITLE_SCRIPT_LOAD }; #define WAIT(t) TITLE_SCRIPT_WAIT, t -#define LOAD() TITLE_SCRIPT_LOAD +#define LOADMM() TITLE_SCRIPT_LOADMM #define LOCATION(x, y) TITLE_SCRIPT_LOCATION, x, y #define ROTATE(n) TITLE_SCRIPT_ROTATE, n +#define ZOOM(d) TITLE_SCRIPT_ZOOM, d #define RESTART() TITLE_SCRIPT_RESTART +#define LOAD(i) TITLE_SCRIPT_LOAD, i static const uint8 _magicMountainScript[] = { - LOAD(), + LOADMM(), LOCATION(210, 112), WAIT(13), ROTATE(1), LOCATION(210, 112), WAIT(14), ROTATE(3), LOCATION(167, 180), WAIT(12), @@ -71,12 +78,13 @@ static const uint8 _magicMountainScript[] = { RESTART(), }; +static uint8* _loadedScript; static const uint8* _currentScript; +static int _scriptNoLoadsSinceRestart; static int _scriptWaitCounter; static void title_init_showcase(); static void title_update_showcase(); -static void title_play_music(); static uint8 *generate_random_script(); @@ -84,14 +92,18 @@ static uint8 *generate_random_script(); static void title_create_windows(); +static uint8 *title_script_load(); + /** * * rct2: 0x0068E8DA */ void title_load() { - if (RCT2_GLOBAL(0x009DEA6E, uint8) & 1) - RCT2_CALLPROC_X(0x00667C15, 0, 1, 0, 0, 0, 0, 0);//Game pause toggle + log_verbose("loading title"); + + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) & 1) + pause_toggle(); RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_TITLE_DEMO; @@ -100,23 +112,33 @@ void title_load() reset_sprite_list(); ride_init_all(); window_guest_list_init_vars_a(); - sub_6BD3A4(); // RCT2_CALLPROC_EBPSAFE(0x006BD3A4); - map_init(); + sub_6BD3A4(); + map_init(150); park_init(); date_reset(); climate_reset(CLIMATE_COOL_AND_WET); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); + scenery_set_default_placement_configuration(); window_new_ride_init_vars(); window_guest_list_init_vars_b(); window_staff_list_init_vars(); - map_update_tile_pointers(); //RCT2_CALLPROC_EBPSAFE(0x0068AFFD); - reset_0x69EBE4();// RCT2_CALLPROC_EBPSAFE(0x0069EBE4); + map_update_tile_pointers(); + reset_0x69EBE4(); + stop_ride_music(); + stop_crowd_sound(); + stop_other_sounds(); viewport_init_all(); news_item_init_queue(); title_create_windows(); title_init_showcase(); gfx_invalidate_screen(); RCT2_GLOBAL(0x009DEA66, uint16) = 0; + + if (gOpenRCT2ShowChangelog) { + gOpenRCT2ShowChangelog = false; + window_changelog_open(); + } + + log_verbose("loading title finished"); } /** @@ -126,13 +148,12 @@ void title_load() */ static void title_create_windows() { - // RCT2_CALLPROC_EBPSAFE(0x0066B3E8); - window_main_open(); window_title_menu_open(); window_title_exit_open(); + window_title_options_open(); window_title_logo_open(); - RCT2_CALLPROC_EBPSAFE(0x0066B905); + window_resize_gui(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)); } /** @@ -141,99 +162,204 @@ static void title_create_windows() */ static void title_init_showcase() { + _scriptNoLoadsSinceRestart = 1; + + SafeFree(_loadedScript); + _currentScript = _magicMountainScript; - if (gRandomShowcase) - _currentScript = generate_random_script(); + switch (gConfigGeneral.title_sequence) { + case TITLE_SEQUENCE_OPENRCT2: + _loadedScript = title_script_load(); + if (_loadedScript != NULL) + _currentScript = _loadedScript; + break; + case TITLE_SEQUENCE_RANDOM: + _loadedScript = generate_random_script(); + _currentScript = _loadedScript; + break; + } + _scriptWaitCounter = 0; title_update_showcase(); } +static int title_load_park(const char *path) +{ + rct_window* w; + int successfulLoad; + + successfulLoad = _strcmpi(path_get_extension(path), ".sv6") == 0 ? + game_load_sv6(path) : + scenario_load(path); + + if (!successfulLoad) + return 0; + + w = window_get_main(); + w->viewport_target_sprite = -1; + w->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16); + w->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16); + + { + char _cl = (RCT2_GLOBAL(0x0138869E, sint16) & 0xFF) - w->viewport->zoom; + w->viewport->zoom = RCT2_GLOBAL(0x0138869E, sint16) & 0xFF; + *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(0x0138869E, sint16) >> 8; + if (_cl != 0) { + if (_cl < 0) { + _cl = -_cl; + w->viewport->view_width >>= _cl; + w->viewport->view_height >>= _cl; + } else { + w->viewport->view_width <<= _cl; + w->viewport->view_height <<= _cl; + } + } + w->saved_view_x -= w->viewport->view_width >> 1; + w->saved_view_y -= w->viewport->view_height >> 1; + } + + window_invalidate(w); + reset_all_sprite_quadrant_placements(); + window_new_ride_init_vars(); + if (_strcmpi(path_get_extension(path), ".sv6") != 0) + sub_684AC3(); + RCT2_CALLPROC_EBPSAFE(0x006DFEE4); + news_item_init_queue(); + gfx_invalidate_screen(); + RCT2_GLOBAL(0x009DEA66, sint16) = 0; + RCT2_GLOBAL(0x009DEA5C, sint16) = 0x0D6D8; + return 1; +} + +static void title_skip_opcode() +{ + uint8 script_opcode; + + script_opcode = *_currentScript++; + switch (script_opcode) { + case TITLE_SCRIPT_WAIT: + _currentScript++; + break; + case TITLE_SCRIPT_LOADMM: + _currentScript++; + break; + case TITLE_SCRIPT_LOCATION: + _currentScript++; + _currentScript++; + break; + case TITLE_SCRIPT_ROTATE: + _currentScript++; + break; + case TITLE_SCRIPT_RESTART: + break; + case TITLE_SCRIPT_LOAD: + do { + _currentScript++; + } while (*(_currentScript - 1) != 0); + break; + } +} + +static void title_do_next_script_opcode() +{ + int i; + short x, y, z; + uint8 script_opcode, script_operand; + rct_window* w; + + script_opcode = *_currentScript++; + switch (script_opcode) { + case TITLE_SCRIPT_WAIT: + _scriptWaitCounter = (*_currentScript++) * 32; + break; + case TITLE_SCRIPT_LOADMM: + if (!title_load_park(get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN))) { + log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); + exit(-1); + } + break; + case TITLE_SCRIPT_LOCATION: + x = (*_currentScript++) * 32 + 16; + y = (*_currentScript++) * 32 + 16; + z = map_element_height(x, y); + + // Update viewport + w = window_get_main(); + if (w != NULL) { + window_scroll_to_location(w, x, y, z); + w->flags &= ~WF_SCROLLING_TO_LOCATION; + viewport_update_position(w); + } + break; + case TITLE_SCRIPT_ROTATE: + script_operand = (*_currentScript++); + w = window_get_main(); + if (w != NULL) + for (i = 0; i < script_operand; i++) + window_rotate_camera(w); + break; + case TITLE_SCRIPT_ZOOM: + script_operand = (*_currentScript++); + w = window_get_main(); + if (w != NULL && w->viewport != NULL) + window_zoom_set(w, script_operand); + break; + case TITLE_SCRIPT_RESTART: + _scriptNoLoadsSinceRestart = 1; + _currentScript = _loadedScript; + if (gRandomShowcase) { + if (_currentScript != NULL) + free((uint8*)_currentScript); + _currentScript = generate_random_script(); + } + break; + case TITLE_SCRIPT_LOAD: + { + const uint8 *loadPtr; + char *ch, filename[32], path[MAX_PATH]; + + loadPtr = _currentScript - 1; + + // Get filename + ch = filename; + do { + *ch++ = *_currentScript++; + } while (*(_currentScript - 1) != 0); + + // Construct full relative path + sprintf(path, "%s%cData%ctitle%c%s", gExePath, platform_get_path_separator(), platform_get_path_separator(), platform_get_path_separator(), filename); + if (title_load_park(path)) { + _scriptNoLoadsSinceRestart = 0; + } else { + script_opcode = *_currentScript; + while (script_opcode != TITLE_SCRIPT_LOADMM && script_opcode != TITLE_SCRIPT_LOAD && script_opcode != TITLE_SCRIPT_RESTART) { + title_skip_opcode(); + script_opcode = *_currentScript; + } + + if (script_opcode == TITLE_SCRIPT_RESTART && _scriptNoLoadsSinceRestart) { + if (_currentScript != _magicMountainScript) { + _currentScript = _magicMountainScript; + } else { + log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); + exit(-1); + } + } + } + } + break; + } +} + /** * * rct2: 0x00678761 */ static void title_update_showcase() { - rct_window* w; - uint8 script_opcode, script_operand; - short x, y, z; - int i; - if (_scriptWaitCounter <= 0) { do { - script_opcode = *_currentScript++; - switch (script_opcode) { - case TITLE_SCRIPT_WAIT: - _scriptWaitCounter = (*_currentScript++) * 32; - break; - case TITLE_SCRIPT_LOAD: - if (!scenario_load(get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN))) { - log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); - exit(-1); - } - - w = window_get_main(); - w->viewport_target_sprite = -1; - w->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16); - w->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16); - - { - char _cl = (RCT2_GLOBAL(0x0138869E, sint16) & 0xFF) - w->viewport->zoom; - w->viewport->zoom = RCT2_GLOBAL(0x0138869E, sint16) & 0xFF; - *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(0x0138869E, sint16) >> 8; - if (_cl != 0) { - if (_cl < 0) { - _cl = -_cl; - w->viewport->view_width >>= _cl; - w->viewport->view_height >>= _cl; - } else { - w->viewport->view_width <<= _cl; - w->viewport->view_height <<= _cl; - } - } - w->saved_view_x -= w->viewport->view_width >> 1; - w->saved_view_y -= w->viewport->view_height >> 1; - } - - window_invalidate(w); - sub_69E9A7(); - window_new_ride_init_vars(); - sub_684AC3(); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); - news_item_init_queue(); - gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, sint16) = 0; - RCT2_GLOBAL(0x009DEA5C, sint16) = 0x0D6D8; - break; - case TITLE_SCRIPT_LOCATION: - x = (*_currentScript++) * 32 + 16; - y = (*_currentScript++) * 32 + 16; - z = map_element_height(x, y); - - // Update viewport - w = window_get_main(); - if (w != NULL) { - window_scroll_to_location(w, x, y, z); - w->flags &= ~0x08; - viewport_update_position(w); - } - break; - case TITLE_SCRIPT_ROTATE: - script_operand = (*_currentScript++); - w = window_get_main(); - if (w != NULL) - for (i = 0; i < script_operand; i++) - window_rotate_camera(w); - break; - case TITLE_SCRIPT_RESTART: - _currentScript = _magicMountainScript; - if (gRandomShowcase) { - if (_currentScript != NULL) - free((uint8*)_currentScript); - _currentScript = generate_random_script(); - } - break; - } + title_do_next_script_opcode(); } while (_scriptWaitCounter == 0); } @@ -250,6 +376,12 @@ static void DrawOpenRCT2(int x, int y) // Format text (name and version) sprintf(buffer, "%c%c%c%s, v%s", FORMAT_MEDIUMFONT, FORMAT_OUTLINE, FORMAT_WHITE, OPENRCT2_NAME, OPENRCT2_VERSION); + if (!str_is_null_or_empty(OPENRCT2_BRANCH)) + sprintf(strchr(buffer, 0), "-%s", OPENRCT2_BRANCH); + if (!str_is_null_or_empty(OPENRCT2_COMMIT_SHA1_SHORT)) + sprintf(strchr(buffer, 0), " (%s)", OPENRCT2_COMMIT_SHA1_SHORT); + if (!str_is_null_or_empty(OPENRCT2_BUILD_SERVER)) + sprintf(strchr(buffer, 0), " provided by %s", OPENRCT2_BUILD_SERVER); // Draw Text gfx_draw_string(dpi, buffer, 0, x + 5, y + 5); @@ -259,39 +391,25 @@ static void DrawOpenRCT2(int x, int y) void game_handle_input(); void title_update() { - int tmp; - screenshot_check(); title_handle_keyboard_input(); - if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) { title_update_showcase(); game_logic_update(); - start_title_music();//title_play_music(); + start_title_music(); } RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~0x80; - RCT2_GLOBAL(0x009AC861, uint16) &= ~0x8000; - RCT2_GLOBAL(0x009AC861, uint16) &= ~0x02; - tmp = RCT2_GLOBAL(0x009AC861, uint16) & 0x01; - RCT2_GLOBAL(0x009AC861, uint16) &= ~0x01; - if (!tmp) - RCT2_GLOBAL(0x009AC861, uint16) |= 0x02; - RCT2_GLOBAL(0x009AC861, uint16) &= ~0x08; - tmp = RCT2_GLOBAL(0x009AC861, uint16) & 0x04; - RCT2_GLOBAL(0x009AC861, uint16) &= ~0x04; - if (!tmp) - RCT2_GLOBAL(0x009AC861, uint16) |= 0x04; window_map_tooltip_update_visibility(); + window_dispatch_update_all(); window_update_all(); DrawOpenRCT2(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 20); RCT2_GLOBAL(0x01388698, uint16)++; // Input - // RCT2_CALLPROC_X(0x00667919, 1, 0, 0, 0, 0, 0, 0); // read_input(1) - // RCT2_CALLPROC_EBPSAFE(0x006EA627); // window_manager_handle_input(); game_handle_input(); update_palette_effects(); @@ -300,42 +418,10 @@ void title_update() if (RCT2_GLOBAL(0x009AAC73, uint8) != 255) { RCT2_GLOBAL(0x009AAC73, uint8)++; if (RCT2_GLOBAL(0x009AAC73, uint8) == 255) - config_save(); + config_save_default(); } } -/** - * - * rct2: 0x00678761 - */ -// this doesn't seem like it is 0x00678761, supposed to be 0x006BD0F8? -static void title_play_music() -{ - RCT2_CALLPROC_EBPSAFE(0x006BD0F8); // play title screen music - - if (!(RCT2_GLOBAL(0x009AF284, uint32) & 1) || !(RCT2_GLOBAL(0x009AF59D, uint8) & 1)) { - if (RCT2_GLOBAL(0x009AF600, uint8) != 0) - stop_title_music(); - return; - } - - if (RCT2_GLOBAL(0x009AF600, uint8) != 0) - return; - - // Play old title music - char musicPath[_MAX_PATH]; - strcpy(musicPath, get_file_path(PATH_ID_CSS17)); - if (gOldMusic) { - strcpy(musicPath, RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char)); - strcat(musicPath, "\\data\\css50.dat"); - } - - if (sound_channel_load_file2(3, musicPath, 0)) // play music - sound_channel_play(3, 1, 0, 0, 0); - - RCT2_GLOBAL(0x009AF600, uint8) = 1; -} - static uint8 *generate_random_script() { int i, j; @@ -364,3 +450,115 @@ static uint8 *generate_random_script() return script; } + +#pragma region Load script.txt + +static void title_script_get_line(FILE *file, char *parts) +{ + int i, c, part, cindex, whitespace, comment; + + for (i = 0; i < 3; i++) + parts[i * 32] = 0; + + part = 0; + cindex = 0; + whitespace = 1; + comment = 0; + for (;;) { + c = fgetc(file); + if (c == '\n' || c == '\r' || c == EOF) { + parts[part * 32 + cindex] = 0; + return; + } else if (c == '#') { + parts[part * 32 + cindex] = 0; + comment = 1; + } else if (c == ' ' && !comment) { + if (!whitespace) { + parts[part * 32 + cindex] = 0; + part++; + cindex = 0; + } + } else if (!comment) { + whitespace = 0; + if (cindex < 31) { + parts[part * 32 + cindex] = c; + cindex++; + } + } + } +} + +static uint8 *title_script_load() +{ + FILE *file; + char parts[3 * 32], *token, *part1, *part2, *src; + + char path[MAX_PATH]; + char filePath[] = "data/title/script.txt"; + + sprintf(path, "%s%c%s", gExePath, platform_get_path_separator(), filePath); + log_verbose("loading title script, %s", path); + file = fopen(path, "r"); + if (file == NULL) { + log_error("unable to load title script"); + return NULL; + } + + uint8 *binaryScript = (uint8*)malloc(1024 * 8); + if (binaryScript == NULL) { + fclose(file); + + log_error("unable to allocate memory for script"); + return NULL; + } + + uint8 *scriptPtr = binaryScript; + + do { + title_script_get_line(file, parts); + + token = &parts[0 * 32]; + part1 = &parts[1 * 32]; + part2 = &parts[2 * 32]; + + if (token[0] != 0) { + if (_stricmp(token, "LOAD") == 0) { + src = part1; + *scriptPtr++ = TITLE_SCRIPT_LOAD; + do { + *scriptPtr++ = *src++; + } while (*(src - 1) != 0); + } else if (_stricmp(token, "LOCATION") == 0) { + *scriptPtr++ = TITLE_SCRIPT_LOCATION; + *scriptPtr++ = atoi(part1) & 0xFF; + *scriptPtr++ = atoi(part2) & 0xFF; + } else if (_stricmp(token, "ROTATE") == 0) { + *scriptPtr++ = TITLE_SCRIPT_ROTATE; + *scriptPtr++ = atoi(part1) & 0xFF; + } else if (_stricmp(token, "ZOOM") == 0) { + *scriptPtr++ = TITLE_SCRIPT_ZOOM; + *scriptPtr++ = atoi(part1) & 0xFF; + } else if (_stricmp(token, "WAIT") == 0) { + *scriptPtr++ = TITLE_SCRIPT_WAIT; + *scriptPtr++ = atoi(part1) & 0xFF; + } else { + log_error("unknown token, %s", token); + return NULL; + } + } + } while (!feof(file)); + fclose(file); + + *scriptPtr++ = TITLE_SCRIPT_RESTART; + + int scriptLength = (int)(scriptPtr - binaryScript); + binaryScript = realloc(binaryScript, scriptLength); + if (binaryScript == NULL) { + log_error("unable to reallocate memory for script"); + return NULL; + } + + return binaryScript; +} + +#pragma endregion diff --git a/src/toolbar.c b/src/toolbar.c deleted file mode 100644 index b04aea397d..0000000000 --- a/src/toolbar.c +++ /dev/null @@ -1,200 +0,0 @@ -/***************************************************************************** -* 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 . -*****************************************************************************/ - -#include "rct2.h" -#include "addresses.h" -#include "input.h" -#include "toolbar.h" -#include "localisation/string_ids.h" -#include "interface/viewport.h" -#include "interface/window.h" -#include "windows/dropdown.h" - -/** -* -* rct2: 0x0066CDE4 -*/ -void top_toolbar_init_view_menu(rct_window* w, rct_widget* widget) { - gDropdownItemsFormat[0] = 1156; - gDropdownItemsFormat[1] = 1156; - gDropdownItemsFormat[2] = 1156; - gDropdownItemsFormat[3] = 0; - gDropdownItemsFormat[4] = 1156; - gDropdownItemsFormat[5] = 1156; - gDropdownItemsFormat[6] = 1156; - gDropdownItemsFormat[7] = 1156; - gDropdownItemsFormat[8] = 0; - gDropdownItemsFormat[9] = 1156; - gDropdownItemsFormat[10] = 1156; - gDropdownItemsFormat[11] = 1156; - - gDropdownItemsArgs[0] = STR_UNDERGROUND_VIEW; - gDropdownItemsArgs[1] = STR_REMOVE_BASE_LAND; - gDropdownItemsArgs[2] = STR_REMOVE_VERTICAL_FACES; - gDropdownItemsArgs[4] = STR_SEE_THROUGH_RIDES; - gDropdownItemsArgs[5] = STR_SEE_THROUGH_SCENERY; - gDropdownItemsArgs[6] = STR_INVISIBLE_SUPPORTS; - gDropdownItemsArgs[7] = STR_INVISIBLE_PEOPLE; - gDropdownItemsArgs[9] = STR_HEIGHT_MARKS_ON_LAND; - gDropdownItemsArgs[10] = STR_HEIGHT_MARKS_ON_RIDE_TRACKS; - gDropdownItemsArgs[11] = STR_HEIGHT_MARKS_ON_PATHS; - - window_dropdown_show_text( - w->x + widget->left, - w->y + widget->top, - widget->bottom - widget->top + 1, - w->colours[1] | 0x80, - 0, - 12 - ); - - // Set checkmarks - rct_viewport* mainViewport = window_get_main()->viewport; - if (mainViewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) - gDropdownItemsChecked |= (1 << 0); - if (mainViewport->flags & VIEWPORT_FLAG_HIDE_BASE) - gDropdownItemsChecked |= (1 << 1); - if (mainViewport->flags & VIEWPORT_FLAG_HIDE_VERTICAL) - gDropdownItemsChecked |= (1 << 2); - if (mainViewport->flags & VIEWPORT_FLAG_SEETHROUGH_RIDES) - gDropdownItemsChecked |= (1 << 4); - if (mainViewport->flags & VIEWPORT_FLAG_SEETHROUGH_SCENERY) - gDropdownItemsChecked |= (1 << 5); - if (mainViewport->flags & VIEWPORT_FLAG_INVISIBLE_SUPPORTS) - gDropdownItemsChecked |= (1 << 6); - if (mainViewport->flags & VIEWPORT_FLAG_INVISIBLE_PEEPS) - gDropdownItemsChecked |= (1 << 7); - if (mainViewport->flags & VIEWPORT_FLAG_LAND_HEIGHTS) - gDropdownItemsChecked |= (1 << 9); - if (mainViewport->flags & VIEWPORT_FLAG_TRACK_HEIGHTS) - gDropdownItemsChecked |= (1 << 10); - if (mainViewport->flags & VIEWPORT_FLAG_PATH_HEIGHTS) - gDropdownItemsChecked |= (1 << 11); - - RCT2_GLOBAL(0x9DEBA2, uint16) = 0; -} - -/** -* -* rct2: 0x0066CF8A -*/ -void top_toolbar_view_menu_dropdown(short dropdownIndex) { - if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x9DEBA2, uint16); - rct_window* w = window_get_main(); - if (w) { - switch (dropdownIndex) { - case DDIDX_UNDERGROUND_INSIDE: - w->viewport->flags ^= VIEWPORT_FLAG_UNDERGROUND_INSIDE; - break; - case DDIDX_HIDE_BASE: - w->viewport->flags ^= VIEWPORT_FLAG_HIDE_BASE; - break; - case DDIDX_HIDE_VERTICAL: - w->viewport->flags ^= VIEWPORT_FLAG_HIDE_VERTICAL; - break; - case DDIDX_SEETHROUGH_RIDES: - w->viewport->flags ^= VIEWPORT_FLAG_SEETHROUGH_RIDES; - break; - case DDIDX_SEETHROUGH_SCENARY: - w->viewport->flags ^= VIEWPORT_FLAG_SEETHROUGH_SCENERY; - break; - case DDIDX_INVISIBLE_SUPPORTS: - w->viewport->flags ^= VIEWPORT_FLAG_INVISIBLE_SUPPORTS; - break; - case DDIDX_INVISIBLE_PEEPS: - w->viewport->flags ^= VIEWPORT_FLAG_INVISIBLE_PEEPS; - break; - case DDIDX_LAND_HEIGHTS: - w->viewport->flags ^= VIEWPORT_FLAG_LAND_HEIGHTS; - break; - case DDIDX_TRACK_HEIGHTS: - w->viewport->flags ^= VIEWPORT_FLAG_TRACK_HEIGHTS; - break; - case DDIDX_PATH_HEIGHTS: - w->viewport->flags ^= VIEWPORT_FLAG_PATH_HEIGHTS; - break; - default: - return; - } - window_invalidate(w); - } -} - - -/** -* -* rct2: 0x0066CCE7 -*/ -void toggle_footpath_window() { - if (window_find_by_class(WC_FOOTPATH) == NULL) { - window_footpath_open(); - } else { - tool_cancel(); - window_close_by_class(WC_FOOTPATH); - } -} - -/* -* -* rct2: 0x0066CD54 -*/ -void toggle_land_window(rct_window* topToolbar, int widgetIndex) { - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 7) { - tool_cancel(); - } else { - show_gridlines(); - tool_set(topToolbar, widgetIndex, 18); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; - window_land_open(); - } -} - -/* -* -* rct2: 0x0066CD0C -*/ -void toggle_clear_scenery_window(rct_window* topToolbar, int widgetIndex) { - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 16) { - tool_cancel(); - } else { - show_gridlines(); - tool_set(topToolbar, widgetIndex, 12); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 2; - window_clear_scenery_open(); - } -} - -/* -* -* rct2: 0x0066CD9C -*/ -void toggle_water_window(rct_window* topToolbar, int widgetIndex) { - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 8) { - tool_cancel(); - } else { - show_gridlines(); - tool_set(topToolbar, widgetIndex, 19); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; - window_water_open(); - } -} \ No newline at end of file diff --git a/src/tutorial.c b/src/tutorial.c index 5fc7972287..778cf47812 100644 --- a/src/tutorial.c +++ b/src/tutorial.c @@ -31,8 +31,6 @@ void tutorial_start(int type) { strcpy((char*)0x009BC677, "Tutorial not implemented."); window_error_open(3165, STR_NONE); - - // RCT2_CALLPROC_X(0x0066ECC1, type, 0, 0, 0, 0, 0, 0); } /** diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index 221d7761fa..f11ddeb7cb 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -89,7 +89,7 @@ int sawyercoding_read_chunk(FILE *file, uint8 *buffer) // Read chunk header if (fread(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file) != 1) { - RCT2_ERROR("Unable to read chunk header!"); + log_error("Unable to read chunk header!"); return -1; } @@ -98,7 +98,7 @@ int sawyercoding_read_chunk(FILE *file, uint8 *buffer) // Read chunk data if (fread(src_buffer, chunkHeader.length, 1, file) != 1) { free(src_buffer); - RCT2_ERROR("Unable to read chunk data!"); + log_error("Unable to read chunk data!"); return -1; } @@ -163,10 +163,14 @@ int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding free(encode_buffer); break; case CHUNK_ENCODING_ROTATE: - encode_chunk_rotate(buffer, chunkHeader.length); + encode_buffer = malloc(chunkHeader.length); + memcpy(encode_buffer, buffer, chunkHeader.length); + encode_chunk_rotate(encode_buffer, chunkHeader.length); memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header)); dst_file += sizeof(sawyercoding_chunk_header); - memcpy(dst_file, buffer, chunkHeader.length); + memcpy(dst_file, encode_buffer, chunkHeader.length); + + free(encode_buffer); break; } @@ -221,6 +225,43 @@ int sawyercoding_decode_td6(char *src, char *dst, int length) return decode_chunk_rle(src, dst, length - 4); } +int sawyercoding_encode_td6(char* src, char* dst, int length){ + int output_length = encode_chunk_rle(src, dst, length); + + uint32 checksum = 0; + for (int i = 0; i < output_length; i++){ + uint8 new_byte = ((checksum & 0xFF) + dst[i]) & 0xFF; + checksum = (checksum & 0xFFFFFF00) + new_byte; + checksum = rol32(checksum, 3); + } + checksum -= 0x1D4C1; + + *((uint32*)&dst[output_length]) = checksum; + output_length += 4; + return output_length; +} + +/* Based off of rct2: 0x006770C1 */ +int sawyercoding_validate_track_checksum(char* src, int length){ + uint32 file_checksum = *((uint32*)&src[length - 4]); + + uint32 checksum = 0; + for (int i = 0; i < length - 4; i++){ + uint8 new_byte = ((checksum & 0xFF) + src[i]) & 0xFF; + checksum = (checksum & 0xFFFFFF00) + new_byte; + checksum = rol32(checksum, 3); + } + + if (checksum - 0x1D4C1 == file_checksum) + return 1; // .TD6 + else if (checksum - 0x1A67C == file_checksum) + return 1; // .TD4 + else if (checksum - 0x1A650 == file_checksum) + return 1; // .TD4 + else + return 0; +} + #pragma region Decoding /** @@ -314,14 +355,14 @@ static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length) while (src < end_src - 1){ - if ((count && *src == src[1]) || count > 120){ + if ((count && *src == src[1]) || count > 125){ *dst++ = count - 1; for (; count != 0; --count){ *dst++ = *src_norm_start++; } } if (*src == src[1]){ - for (; (count < 120) && ((src + count) < end_src); count++){ + for (; (count < 125) && ((src + count) < end_src); count++){ if (*src != src[count]) break; } *dst++ = 257 - count; @@ -412,3 +453,28 @@ static void encode_chunk_rotate(char *buffer, int length) } #pragma endregion + +int sawyercoding_detect_file_type(char *src, int length) +{ + int i; + + // Currently can't detect TD4, as the checksum is the same as SC4 (need alternative method) + + uint32 checksum = *((uint32*)&src[length - 4]); + uint32 actualChecksum = 0; + for (i = 0; i < length - 4; i++) { + actualChecksum = (actualChecksum & 0xFFFFFF00) | (((actualChecksum & 0xFF) + (uint8)src[i]) & 0xFF); + actualChecksum = rol32(actualChecksum, 3); + } + + switch (checksum - actualChecksum) { + case +108156: return FILE_VERSION_RCT1 | FILE_TYPE_SV4; + case -108156: return FILE_VERSION_RCT1 | FILE_TYPE_SC4; + case +110001: return FILE_VERSION_RCT1_AA | FILE_TYPE_SV4; + case -110001: return FILE_VERSION_RCT1_AA | FILE_TYPE_SC4; + case +120001: return FILE_VERSION_RCT1_LL | FILE_TYPE_SV4; + case -120001: return FILE_VERSION_RCT1_LL | FILE_TYPE_SC4; + } + + return -1; +} \ No newline at end of file diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index d7993d391a..a1c702b334 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -35,6 +35,18 @@ enum { CHUNK_ENCODING_ROTATE }; +enum { + FILE_VERSION_MASK = (3 << 0), + FILE_VERSION_RCT1 = (0 << 0), + FILE_VERSION_RCT1_AA = (1 << 0), + FILE_VERSION_RCT1_LL = (2 << 0), + + FILE_TYPE_MASK = (3 << 2), + FILE_TYPE_TD4 = (0 << 2), + FILE_TYPE_SV4 = (1 << 2), + FILE_TYPE_SC4 = (2 << 2) +}; + int sawyercoding_validate_checksum(FILE *file); uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length); int sawyercoding_read_chunk(FILE *file, uint8 *buffer); @@ -43,5 +55,9 @@ 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); int sawyercoding_decode_td6(char *src, char *dst, int length); +int sawyercoding_encode_td6(char* src, char* dst, int length); +int sawyercoding_validate_track_checksum(char* src, int length); + +int sawyercoding_detect_file_type(char *src, int length); #endif diff --git a/src/util/util.c b/src/util/util.c index 8abdaca2ca..bf856238fa 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -41,17 +41,64 @@ int mph_to_kmph(int mph) return (mph * 1648) / 1024; } -void path_set_extension(char *path, const char *extension) +const char *path_get_filename(const char *path) { - char *ch = path; - while (*ch != '.' && *ch != 0) { - ch++; + const char *result, *ch; + + result = path; + for (ch = path; *ch != 0; ch++) { + if (*ch == '/' || *ch == '\\') { + if (*(ch + 1) != 0) + result = ch + 1; + } } - if (extension[0] != '.') - *ch++ = '.'; + return result; +} - strcpy(ch, extension); +const char *path_get_extension(const char *path) +{ + const char *extension = NULL; + const char *ch = path; + while (*ch != 0) { + if (*ch == '.') + extension = ch; + + ch++; + } + if (extension == NULL) + extension = ch; + return extension; +} + +void path_set_extension(char *path, const char *newExtension) +{ + char *extension = NULL; + char *ch = path; + while (*ch != 0) { + if (*ch == '.') + extension = ch; + + ch++; + } + if (extension == NULL) + extension = ch; + + if (newExtension[0] != '.') + *extension++ = '.'; + + strcpy(extension, newExtension); +} + +void path_remove_extension(char *path) +{ + char *ch = path + strlen(path); + for (--ch; ch >= path; --ch) { + if (*ch == '.') { + *ch = '\0'; + break; + } + } } long fsize(FILE *fp) @@ -66,6 +113,32 @@ long fsize(FILE *fp) return size; } +bool readentirefile(const char *path, void **outBuffer, long *outLength) +{ + FILE *fp; + long fpLength; + void *fpBuffer; + + // Open file + fp = fopen(path, "rb"); + if (fp == NULL) + 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); + + *outBuffer = fpBuffer; + *outLength = fpLength; + return 1; +} + int bitscanforward(int source) { int i; @@ -75,4 +148,31 @@ int bitscanforward(int source) return i; return -1; +} + +bool strequals(const char *a, const char *b, int length, bool caseInsensitive) +{ + return caseInsensitive ? + _strnicmp(a, b, length) == 0 : + strncmp(a, b, length) == 0; +} + +/* case insensitve compare */ +int strcicmp(char const *a, char const *b) +{ + for (;; a++, b++) { + int d = tolower(*a) - tolower(*b); + if (d != 0 || !*a) + return d; + } +} + +bool utf8_is_bom(const char *str) +{ + return str[0] == 0xEF && str[1] == 0xBB && str[2] == 0xBF; +} + +bool str_is_null_or_empty(const char *str) +{ + return str == NULL || str[0] == 0; } \ No newline at end of file diff --git a/src/util/util.h b/src/util/util.h index 82098918be..e8d8cca36d 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -27,9 +27,18 @@ int squaredmetres_to_squaredfeet(int squaredMetres); int metres_to_feet(int metres); int mph_to_kmph(int mph); -void path_set_extension(char *path, const char *extension); +const char *path_get_filename(const char *path); +const char *path_get_extension(const char *path); +void path_set_extension(char *path, const char *newExtension); +void path_remove_extension(char *path); long fsize(FILE *fp); +bool readentirefile(const char *path, void **outBuffer, long *outLength); int bitscanforward(int source); +bool strequals(const char *a, const char *b, int length, bool caseInsensitive); +int strcicmp(char const *a, char const *b); + +bool utf8_is_bom(const char *str); +bool str_is_null_or_empty(const char *str); #endif diff --git a/src/windows/about.c b/src/windows/about.c index 78922b0c05..9cc7045cd9 100644 --- a/src/windows/about.c +++ b/src/windows/about.c @@ -23,6 +23,7 @@ #include "../sprites.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../interface/themes.h" enum WINDOW_ABOUT_WIDGET_IDX { WIDX_BACKGROUND, @@ -89,9 +90,7 @@ void window_about_open() if (window != NULL) return; - window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 200, - max(28, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 165), + window = window_create_centred( 400, 330, (uint32*)window_about_events, diff --git a/src/windows/banner.c b/src/windows/banner.c index 3fc77ed2f1..b33b94fcdb 100644 --- a/src/windows/banner.c +++ b/src/windows/banner.c @@ -31,6 +31,7 @@ #include "error.h" #include "dropdown.h" #include "../drawing/drawing.h" +#include "../interface/themes.h" #define WW 113 #define WH 96 @@ -117,7 +118,7 @@ void window_banner_open(rct_windownumber number) if (w != NULL) return; - w = window_create_auto_pos(WW, WH, (uint32*)window_banner_events, WC_BANNER, 0); + w = window_create_auto_pos(WW, WH, (uint32*)window_banner_events, WC_BANNER, WF_2); w->widgets = window_banner_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -130,19 +131,18 @@ void window_banner_open(rct_windownumber number) w->number = number; window_init_scroll_widgets(w); - w->colours[0] = 24; - w->colours[1] = 24; - w->colours[2] = 24; int view_x = gBanners[w->number].x << 5; int view_y = gBanners[w->number].y << 5; - int ebp = ((view_y << 8) | view_x) >> 5; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(ebp); - - while(1){ - if (((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_BANNER) && - (map_element->properties.banner.index == w->number)) break; + rct_map_element* map_element = map_get_first_element_at(view_x / 32, view_y / 32); + while(1) { + if ( + (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_BANNER) && + (map_element->properties.banner.index == w->number) + ) { + break; + } map_element++; } @@ -170,7 +170,6 @@ void window_banner_open(rct_windownumber number) ); w->viewport->flags = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES) ? VIEWPORT_FLAG_GRIDLINES : 0; - w->flags |= WF_2; window_invalidate(w); } @@ -186,10 +185,10 @@ static void window_banner_mouseup() int x = banner->x << 5; int y = banner->y << 5; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(((y << 8) | x) >> 5); + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); while (1){ - if (((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_BANNER) && + if ((map_element_get_type(map_element) == MAP_ELEMENT_TYPE_BANNER) && (map_element->properties.banner.index == w->number)) break; map_element++; } @@ -199,13 +198,13 @@ static void window_banner_mouseup() window_close(w); break; case WIDX_BANNER_DEMOLISH: - game_do_command(x, 1, y, map_element->base_height | (map_element->properties.banner.position << 8), GAME_COMMAND_51, 0, 0); + game_do_command(x, 1, y, map_element->base_height | (map_element->properties.banner.position << 8), GAME_COMMAND_REMOVE_BANNER, 0, 0); break; case WIDX_BANNER_TEXT: - window_text_input_open(w, WIDX_BANNER_TEXT, 2982, 2983, gBanners[w->number].string_idx, 0); + window_text_input_open(w, WIDX_BANNER_TEXT, 2982, 2983, gBanners[w->number].string_idx, 0, 32); break; case WIDX_BANNER_NO_ENTRY: - RCT2_CALLPROC_EBPSAFE(0x006EE3C3); + textinput_cancel(); banner->flags ^= BANNER_FLAG_NO_ENTRY; window_invalidate(w); @@ -242,7 +241,7 @@ static void window_banner_mousedown(int widgetIndex, rct_window*w, rct_widget* w widget->top + w->y, widget->bottom - widget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, 13, widget->right - widget->left - 3); @@ -285,17 +284,13 @@ static void window_banner_dropdown() text_buffer[0] = banner->text_colour + FORMAT_COLOUR_CODE_START; - int string_id = 0, ebx = 0, ecx = 128, edx = 0, ebp = 0, esi = 0; - // Allocate text_buffer to a new string_id? - RCT2_CALLFUNC_X(0x6C421D, &string_id, &ebx, &ecx, &edx, &esi, (int*)&text_buffer, &ebp); - - if (string_id){ + rct_string_id stringId = user_string_allocate(128, text_buffer); + if (stringId != 0) { rct_string_id prev_string_id = banner->string_idx; - banner->string_idx = string_id; + banner->string_idx = stringId; user_string_free(prev_string_id); window_invalidate(w); - } - else{ + } else { window_error_open(2984, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); } break; @@ -322,16 +317,13 @@ static void window_banner_textinput() text_buffer[0] = banner->text_colour + FORMAT_COLOUR_CODE_START; strncpy(text_buffer + 1, text, 32); - int string_id = 0, ebx = 0, ecx = 128, edx = 0, ebp = 0, esi = 0; - RCT2_CALLFUNC_X(0x6C421D, &string_id, &ebx, &ecx, &edx, &esi, (int*)&text_buffer, &ebp); - - if (string_id){ + rct_string_id stringId = user_string_allocate(128, text_buffer); + if (stringId) { rct_string_id prev_string_id = banner->string_idx; - banner->string_idx = string_id; + banner->string_idx = stringId; user_string_free(prev_string_id); window_invalidate(w); - } - else{ + } else { window_error_open(2984, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); } } @@ -343,6 +335,7 @@ static void window_banner_invalidate() rct_window* w; window_get_register(w); + colour_scheme_update(w); rct_banner* banner = &gBanners[w->number]; rct_widget* colour_btn = &window_banner_widgets[WIDX_MAIN_COLOR]; diff --git a/src/windows/changelog.c b/src/windows/changelog.c new file mode 100644 index 0000000000..1faa85ba46 --- /dev/null +++ b/src/windows/changelog.c @@ -0,0 +1,279 @@ +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../interface/viewport.h" +#include "../world/scenery.h" +#include "../world/map.h" +#include "../world/footpath.h" +#include "../util/util.h" +#include "../openrct2.h" +#include "../platform/platform.h" + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_CONTENT_PANEL, + WIDX_SCROLL +}; + +#define WW 500 +#define WH 400 +#define MIN_WW 300 +#define MIN_WH 200 + +rct_widget window_changelog_widgets[] = { + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_CHANGELOG_TITLE, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_RESIZE, 1, 0, WW - 1, 14, WH - 1, 0x0FFFFFFFF, STR_NONE }, // content panel + { WWT_SCROLL, 1, 3, WW - 3, 16, WH - 15, 3, STR_NONE }, // scroll area + { WIDGETS_END }, +}; + +static void window_changelog_emptysub() { } +static void window_changelog_close(); +static void window_changelog_mouseup(); +static void window_changelog_resize(); +static void window_changelog_scrollgetsize(); +static void window_changelog_invalidate(); +static void window_changelog_paint(); +static void window_changelog_scrollpaint(); + +static void* window_changelog_events[] = { + window_changelog_close, + window_changelog_mouseup, + window_changelog_resize, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_scrollgetsize, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_emptysub, + window_changelog_invalidate, + window_changelog_paint, + window_changelog_scrollpaint +}; + +static bool window_changelog_read_file(); +static void window_changelog_dispose_file(); + +static char *_changelogText = NULL; +static long _changelogTextSize = 0; +static char **_changelogLines = NULL; +static int _changelogNumLines = 0; +static int _changelogLongestLineWidth = 0; + +rct_window *window_changelog_open() +{ + rct_window* window; + + window = window_bring_to_front_by_class(WC_CHANGELOG); + if (window != NULL) + return window; + + if (!window_changelog_read_file()) + return NULL; + + int screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + int screenHeight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); + + window = window_create_centred( + screenWidth * 4 / 5, + screenHeight * 4 / 5, + (uint32*)window_changelog_events, + WC_CHANGELOG, + WF_RESIZABLE + ); + window->widgets = window_changelog_widgets; + window->enabled_widgets = (1 << WIDX_CLOSE); + + window_init_scroll_widgets(window); + window->colours[0] = 7; + window->colours[1] = 7; + window->colours[2] = 7; + window->min_width = MIN_WW; + window->min_height = MIN_WH; + window->max_width = MIN_WW; + window->max_height = MIN_WH; + return window; +} + +static void window_changelog_close() +{ + window_changelog_dispose_file(); +} + +static void window_changelog_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + } +} + +static void window_changelog_resize() +{ + rct_window *w; + + window_get_register(w); + + int screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + int screenHeight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); + + w->max_width = (screenWidth * 4) / 5; + w->max_height = (screenHeight * 4) / 5; + + w->min_width = MIN_WW; + w->min_height = MIN_WH; + if (w->width < w->min_width) { + window_invalidate(w); + w->width = w->min_width; + } + if (w->height < w->min_height) { + window_invalidate(w); + w->height = w->min_height; + } +} + +static void window_changelog_scrollgetsize() +{ + rct_window *w; + int width, height; + window_get_register(w); + + width = _changelogLongestLineWidth + 4; + height = _changelogNumLines * 11; + + window_scrollsize_set_registers(width, height); +} + +static void window_changelog_invalidate() +{ + rct_window *w; + + window_get_register(w); + + window_changelog_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_changelog_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + window_changelog_widgets[WIDX_TITLE].right = w->width - 2; + window_changelog_widgets[WIDX_CLOSE].left = w->width - 13; + window_changelog_widgets[WIDX_CLOSE].right = w->width - 3; + window_changelog_widgets[WIDX_CONTENT_PANEL].right = w->width - 1; + window_changelog_widgets[WIDX_CONTENT_PANEL].bottom = w->height - 1; + window_changelog_widgets[WIDX_SCROLL].right = w->width - 3; + window_changelog_widgets[WIDX_SCROLL].bottom = w->height - 15; +} + +static void window_changelog_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); +} + +static void window_changelog_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + uint16 *currentFontFlags = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + sint16 *currentFontSpriteBase = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16); + *currentFontFlags = 0; + *currentFontSpriteBase = 224; + gfx_draw_string(dpi, (char*)0x009C383D, 1, dpi->x, dpi->y); + + int x = 3; + int y = 3; + for (int i = 0; i < _changelogNumLines; i++) { + gfx_draw_string(dpi, _changelogLines[i], 254, x, y); + y += 11; + } +} + +static bool window_changelog_read_file() +{ + window_changelog_dispose_file(); + char path[MAX_PATH]; + sprintf(path, "%s%cchangelog.txt", gExePath, platform_get_path_separator()); + if (!readentirefile(path, &_changelogText, &_changelogTextSize)) { + log_error("Unable to read changelog.txt"); + return false; + } + _changelogText = realloc(_changelogText, _changelogTextSize + 1); + _changelogText[_changelogTextSize++] = 0; + + char *start = _changelogText; + if (_changelogTextSize >= 3 && utf8_is_bom(_changelogText)) + start += 3; + + int changelogLinesCapacity = 8; + _changelogLines = malloc(changelogLinesCapacity * sizeof(char*)); + _changelogLines[0] = start; + _changelogNumLines = 1; + + char *ch = start; + while (*ch != 0) { + unsigned char c = *ch; + if (c == '\n') { + *ch++ = 0; + _changelogNumLines++; + if (_changelogNumLines > changelogLinesCapacity) { + changelogLinesCapacity *= 2; + _changelogLines = realloc(_changelogLines, changelogLinesCapacity * sizeof(char*)); + } + _changelogLines[_changelogNumLines - 1] = ch; + } else if (c < 32 || c > 122) { + // A character that won't be drawn or change state. + *ch++ = FORMAT_OUTLINE_OFF; + } else { + ch++; + } + } + + _changelogLines = realloc(_changelogLines, _changelogNumLines * sizeof(char*)); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + _changelogLongestLineWidth = 0; + for (int i = 0; i < _changelogNumLines; i++) { + int width = gfx_get_string_width(_changelogLines[i]); + _changelogLongestLineWidth = max(width, _changelogLongestLineWidth); + } + return true; +} + +static void window_changelog_dispose_file() +{ + SafeFree(_changelogText); + SafeFree(_changelogLines); + _changelogTextSize = 0; + _changelogNumLines = 0; +} \ No newline at end of file diff --git a/src/windows/cheats.c b/src/windows/cheats.c index c400bb42ed..3048369028 100644 --- a/src/windows/cheats.c +++ b/src/windows/cheats.c @@ -19,26 +19,32 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" +#include "../world/park.h" #include "../peep/peep.h" #include "../ride/ride.h" #include "../scenario.h" #include "../sprites.h" #include "../world/climate.h" +#include "../world/footpath.h" #include "../world/park.h" #include "../world/sprite.h" +#include "../interface/themes.h" +#include "../cheats.h" //#define WW 200 //#define WH 128 -#define CHEATS_MONEY_INCREMENT 50000 -#define CHEATS_TRAM_INCREMENT 1000 +#define CHEATS_MONEY_INCREMENT MONEY(5000,00) +#define CHEATS_TRAM_INCREMENT 250 enum { WINDOW_CHEATS_PAGE_MONEY, WINDOW_CHEATS_PAGE_GUESTS, WINDOW_CHEATS_PAGE_MISC, + WINDOW_CHEATS_PAGE_RIDES, }; enum WINDOW_CHEATS_WIDGET_IDX { @@ -49,18 +55,35 @@ enum WINDOW_CHEATS_WIDGET_IDX { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3, + WIDX_TAB_4, WIDX_HIGH_MONEY, WIDX_PARK_ENTRANCE_FEE, - WIDX_HAPPY_GUESTS = 7, //Same as HIGH_MONEY as it is also the 7th widget but on a different page + WIDX_CLEAR_LOAN, + WIDX_HAPPY_GUESTS = 8, //Same as HIGH_MONEY as it is also the 8th widget but on a different page WIDX_TRAM_GUESTS, - WIDX_FREEZE_CLIMATE = 7, + WIDX_NAUSEA_GUESTS, + WIDX_EXPLODE_GUESTS, + WIDX_FREEZE_CLIMATE = 8, WIDX_OPEN_CLOSE_PARK, - WIDX_DECREASE_GAME_SPEED, - WIDX_INCREASE_GAME_SPEED, WIDX_ZERO_CLEARANCE, WIDX_WEATHER_SUN, - WIDX_WEATHER_THUNDER - + WIDX_WEATHER_THUNDER, + WIDX_CLEAR_GRASS, + WIDX_MOWED_GRASS, + WIDX_WATER_PLANTS, + WIDX_FIX_VANDALISM, + WIDX_REMOVE_LITTER, + WIDX_WIN_SCENARIO, + WIDX_UNLOCK_ALL_PRICES, + WIDX_SANDBOX_MODE, + WIDX_RENEW_RIDES = 8, + WIDX_REMOVE_SIX_FLAGS, + WIDX_MAKE_DESTRUCTIBLE, + WIDX_FIX_ALL, + WIDX_FAST_LIFT_HILL, + WIDX_DISABLE_BRAKES_FAILURE, + WIDX_DISABLE_ALL_BREAKDOWNS, + WIDX_BUILD_IN_PAUSE_MODE }; #pragma region MEASUREMENTS @@ -70,59 +93,94 @@ enum WINDOW_CHEATS_WIDGET_IDX { #define XSPA 5 //X spacing #define YSPA 5 //Y spacing #define XOS 0 + XSPA //X offset from left -#define YOS TAB_HEIGHT + YSPA //Y offset ofrom top (includes tabs height) +#define YOS TAB_HEIGHT + YSPA //Y offset from top (includes tabs height) #define BTNW 110 //button width #define BTNH 16 //button height +#define OPTW 220 //Option (checkbox) width (two colums) +#define OPTH 10 //Option (checkbox) height (two colums) #define YPL(ROW) YOS + ((BTNH + YSPA) * ROW) #define HPL(ROW) YPL(ROW) + BTNH +#define OHPL(ROW) YPL(ROW) + OPTH #define XPL(COL) XOS + ((BTNW + XSPA) * COL) #define WPL(COL) XPL(COL) + BTNW +#define OWPL XPL(0) + OPTW #define TXTO 3 //text horizontal offset from button left (for button text) #pragma endregion static rct_widget window_cheats_money_widgets[] = { - { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535}, // panel / background - { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 3165, STR_WINDOW_TITLE_TIP}, // title bar - { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP}, // close x button - { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535}, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462}, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462}, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2462}, // tab 3 - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2760, STR_NONE}, // high money - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), 2761, STR_NONE}, //Park Entrance Fee Toggle + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535}, // panel / background + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_CHEAT_TITLE_FINANCIAL, STR_WINDOW_TITLE_TIP}, // title bar + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP}, // close x button + { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535}, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_FINANCIAL_CHEATS_TIP }, // tab 1 + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_GUEST_CHEATS_TIP }, // tab 2 + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_CHEATS_TIP }, // tab 3 + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_RIDE_CHEATS_TIP }, // tab 4 + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_CHEAT_5K_MONEY, STR_NONE}, // high money + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), STR_CHEAT_PAY_ENTRANCE, STR_NONE}, // Park Entrance Fee Toggle + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(5), HPL(5), STR_CHEAT_CLEAR_LOAN, STR_NONE }, // Clear loan { WIDGETS_END }, }; static rct_widget window_cheats_guests_widgets[] = { - { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535 }, // panel / background - { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 3165, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535 }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462 }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462 }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2462 }, // tab 3 - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2764, STR_NONE}, // happy guests - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), 2765, STR_NONE}, // happy guests + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535 }, // panel / background + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_CHEAT_TITLE_GUEST, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535 }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_FINANCIAL_CHEATS_TIP }, // tab 1 + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_GUEST_CHEATS_TIP }, // tab 2 + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_CHEATS_TIP }, // tab 3 + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_RIDE_CHEATS_TIP }, // tab 4 + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_CHEAT_HAPPY_GUESTS, STR_NONE}, // happy guests + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), STR_CHEAT_LARGE_TRAM_GUESTS, STR_NONE}, // large tram + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(5), HPL(5), STR_CHEAT_NAUSEA, STR_NONE}, // nausea + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(7), HPL(7), STR_CHEAT_EXPLODE, STR_NONE}, // explode guests { WIDGETS_END }, }; //Strings for following moved to window_cheats_paint() static rct_widget window_cheats_misc_widgets[] = { - { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535 }, // panel / background - { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 3165, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535 }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462 }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462 }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2462}, // tab 3 - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(0), HPL(0), 2767, STR_NONE}, // Freeze climate - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2769, STR_NONE}, // open / close park - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(2), HPL(2), 2771, STR_NONE}, // decrease game speed - { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(2), HPL(2), 2772, STR_NONE}, // increase game speed - { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(3), HPL(3), 2759, STR_NONE}, // Zero Clearance - { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(4), HPL(4), 2757, STR_NONE}, // Sun - { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(4), HPL(4), 2758, STR_NONE}, // Thunder + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535 }, // panel / background + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_CHEAT_TITLE_PARK, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535 }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_FINANCIAL_CHEATS_TIP }, // tab 1 + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_GUEST_CHEATS_TIP }, // tab 2 + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_CHEATS_TIP }, // tab 3 + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_RIDE_CHEATS_TIP }, // tab 4 + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(1), HPL(1), STR_CHEAT_FREEZE_CLIMATE, STR_NONE}, // Freeze climate + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(0), HPL(0), STR_CHEAT_OPEN_PARK, STR_NONE}, // open / close park + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_CHEAT_ZERO_CLEARANCE, STR_NONE}, // Zero Clearance + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(2), HPL(2), STR_CHEAT_FORCE_SUN, STR_NONE}, // Sun + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(2), HPL(2), STR_CHEAT_FORCE_THUNDER, STR_NONE}, // Thunder + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), STR_CHEAT_CLEAR_GRASS, STR_NONE}, // Clear grass + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(3), HPL(3), STR_CHEAT_MOWED_GRASS, STR_NONE}, // Mowed grass + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(4), HPL(4), STR_CHEAT_WATER_PLANTS, STR_NONE}, // Water plants + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(4), HPL(4), STR_CHEAT_FIX_VANDALISM, STR_NONE}, // Fix vandalism + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(5), HPL(5), STR_CHEAT_REMOVE_LITTER, STR_NONE}, // Remove litter + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(0), HPL(0), STR_CHEAT_WIN_SCENARIO, STR_NONE}, // Win scenario + { WWT_CHECKBOX, 1, XPL(0), OWPL, YPL(8),OHPL(8), STR_CHEAT_UNLOCK_PRICES, STR_NONE}, // Unlock all prices + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(5), HPL(5), STR_CHEAT_SANDBOX_MODE, STR_CHEAT_SANDBOX_MODE_TIP},// Sandbox mode (edit land ownership in-game) + { WIDGETS_END }, +}; +static rct_widget window_cheats_rides_widgets[] = { + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535 }, // panel / background + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_CHEAT_TITLE_RIDE, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535 }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_FINANCIAL_CHEATS_TIP }, // tab 1 + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_GUEST_CHEATS_TIP }, // tab 2 + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_CHEATS_TIP }, // tab 3 + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_RIDE_CHEATS_TIP }, // tab 4 + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(0), HPL(0), STR_CHEAT_RENEW_RIDES, STR_NONE}, // Renew rides + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(0), HPL(0), STR_CHEAT_REMOVE_FLAGS, STR_NONE}, // Remove flags + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(1), HPL(1), STR_CHEAT_MAKE_DESTRUCTABLE, STR_NONE}, // Make destructable + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_CHEAT_FIX_ALL_RIDES, STR_NONE }, // Fix all rides + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(8),OHPL(8), STR_CHEAT_410_HILL_LIFT, STR_NONE }, // 410 km/h lift hill + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(6),OHPL(6), STR_CHEAT_DISABLE_BRAKES_FAILURE,STR_NONE }, // Disable brakes failure + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(7),OHPL(7), STR_CHEAT_DISABLE_BREAKDOWNS, STR_NONE }, // Disable all breakdowns + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(5),OHPL(5), STR_CHEAT_BUILD_IN_PAUSE_MODE, STR_NONE }, // Build in pause mode { WIDGETS_END }, }; @@ -130,14 +188,16 @@ static rct_widget *window_cheats_page_widgets[] = { window_cheats_money_widgets, window_cheats_guests_widgets, window_cheats_misc_widgets, + window_cheats_rides_widgets, }; static void window_cheats_emptysub() { } static void window_cheats_money_mouseup(); static void window_cheats_guests_mouseup(); static void window_cheats_misc_mouseup(); -void window_cheats_misc_tool_update(); -void window_cheats_misc_tool_down(); +static void window_cheats_rides_mouseup(); +static void window_cheats_misc_tool_update(); +static void window_cheats_misc_tool_down(); static void window_cheats_update(rct_window *w); static void window_cheats_invalidate(); static void window_cheats_paint(); @@ -236,20 +296,258 @@ static void* window_cheats_misc_events[] = { window_cheats_emptysub }; +static void* window_cheats_rides_events[] = { + window_cheats_emptysub, + window_cheats_rides_mouseup, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_update, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_invalidate, + window_cheats_paint, + window_cheats_emptysub +}; + + static void* window_cheats_page_events[] = { window_cheats_money_events, window_cheats_guests_events, window_cheats_misc_events, + window_cheats_rides_events, }; static uint32 window_cheats_page_enabled_widgets[] = { - (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_HIGH_MONEY) | (1 << WIDX_PARK_ENTRANCE_FEE), - (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_HAPPY_GUESTS) | (1 << WIDX_TRAM_GUESTS), - (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_FREEZE_CLIMATE) | (1 << WIDX_OPEN_CLOSE_PARK) | (1 << WIDX_DECREASE_GAME_SPEED) | (1 << WIDX_INCREASE_GAME_SPEED) | (1 << WIDX_ZERO_CLEARANCE) | (1 << WIDX_WEATHER_SUN) | (1 << WIDX_WEATHER_THUNDER), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_TAB_4) | (1 << WIDX_HIGH_MONEY) | (1 << WIDX_PARK_ENTRANCE_FEE) | (1 << WIDX_CLEAR_LOAN), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_TAB_4) | (1 << WIDX_HAPPY_GUESTS) | (1 << WIDX_TRAM_GUESTS) | (1 << WIDX_NAUSEA_GUESTS) | (1 << WIDX_EXPLODE_GUESTS), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_TAB_4) | (1 << WIDX_FREEZE_CLIMATE) | (1 << WIDX_OPEN_CLOSE_PARK) | (1 << WIDX_ZERO_CLEARANCE) | (1 << WIDX_WEATHER_SUN) | (1 << WIDX_WEATHER_THUNDER) | (1 << WIDX_CLEAR_GRASS) | (1 << WIDX_MOWED_GRASS) | (1 << WIDX_WATER_PLANTS) | (1 << WIDX_FIX_VANDALISM) | (1 << WIDX_REMOVE_LITTER) | (1 << WIDX_WIN_SCENARIO) | (1 << WIDX_UNLOCK_ALL_PRICES) | (1 << WIDX_SANDBOX_MODE), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_TAB_4) | (1 << WIDX_RENEW_RIDES) | (1 << WIDX_REMOVE_SIX_FLAGS) | (1 << WIDX_MAKE_DESTRUCTIBLE) | (1 << WIDX_FIX_ALL) | (1 << WIDX_FAST_LIFT_HILL) | (1 << WIDX_DISABLE_BRAKES_FAILURE) | (1 << WIDX_DISABLE_ALL_BREAKDOWNS) | (1 << WIDX_BUILD_IN_PAUSE_MODE) }; static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); +#pragma region Cheat functions + +static void cheat_set_grass_length(int length) +{ + int x, y; + rct_map_element *mapElement; + + for (y = 0; y < 256; y++) { + for (x = 0; x < 256; x++) { + mapElement = map_get_surface_element_at(x, y); + if (!(mapElement->properties.surface.ownership & OWNERSHIP_OWNED)) + continue; + + if (map_element_get_terrain(mapElement) != TERRAIN_GRASS) + continue; + + if ((mapElement->properties.surface.terrain & 0x1F) > 0) + continue; + + mapElement->properties.surface.grass_length = length; + } + } + + gfx_invalidate_screen(); +} + +static void cheat_water_plants() +{ + map_element_iterator it; + + map_element_iterator_begin(&it); + do { + if (map_element_get_type(it.element) == MAP_ELEMENT_TYPE_SCENERY) { + it.element->properties.scenery.age = 0; + } + } while (map_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +static void cheat_fix_vandalism() +{ + map_element_iterator it; + + map_element_iterator_begin(&it); + do { + if (map_element_get_type(it.element) != MAP_ELEMENT_TYPE_PATH) + continue; + + if ((it.element->properties.path.additions & 0x0F) == 0) + continue; + + it.element->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + } while (map_element_iterator_next(&it)); + + gfx_invalidate_screen(); +} + +static void cheat_remove_litter() +{ + rct_litter* litter; + uint16 spriteIndex, nextSpriteIndex; + + for (spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_LITTER, uint16); spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex) { + litter = &(g_sprite_list[spriteIndex].litter); + nextSpriteIndex = litter->next; + sprite_remove((rct_sprite*)litter); + } + + gfx_invalidate_screen(); +} + +static void cheat_fix_rides() +{ + int rideIndex; + rct_ride *ride; + rct_peep *mechanic; + + FOR_ALL_RIDES(rideIndex, ride) + { + if ((ride->mechanic_status != RIDE_MECHANIC_STATUS_FIXING) && (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN))) + { + mechanic = ride_get_assigned_mechanic(ride); + + if (mechanic != NULL){ + remove_peep_from_ride(mechanic); + } + + RCT2_CALLPROC_X(0x006B7481, 0, 0, 0, rideIndex, 0, 0, 0); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; + } + } +} + +static void cheat_renew_rides() +{ + int i; + rct_ride *ride; + + FOR_ALL_RIDES(i, ride) + { + // Set build date to current date (so the ride is brand new) + ride->build_date = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); + // Set reliability to 100 + ride->reliability = (100 << 8); + } + window_invalidate_by_class(WC_RIDE); +} + +static void cheat_remove_six_flags() +{ + int i; + rct_ride *ride; + FOR_ALL_RIDES(i, ride) + { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) + ride->lifecycle_flags&=~RIDE_LIFECYCLE_SIX_FLAGS; + } + window_invalidate_by_class(WC_RIDE); +} + +static void cheat_make_destructible() +{ + int i; + rct_ride *ride; + FOR_ALL_RIDES(i, ride) + { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE) + ride->lifecycle_flags&=~RIDE_LIFECYCLE_INDESTRUCTIBLE; + } + window_invalidate_by_class(WC_RIDE); +} + +static void cheat_increase_money(money32 amount) +{ + money32 currentMoney; + + currentMoney = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32)); + if (currentMoney < INT_MAX - amount) + currentMoney += amount; + else + currentMoney = INT_MAX; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(currentMoney); + + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +static void cheat_clear_loan() +{ + // First give money + cheat_increase_money(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32)); + + // Then pay the loan + money32 newLoan; + newLoan = MONEY(0, 00); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, newLoan, GAME_COMMAND_SET_CURRENT_LOAN, 0, 0); +} + +static void cheat_generate_guests(int count) +{ + int i; + + for (i = 0; i < count; i++) + generate_new_guest(); + + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); +} + +static void cheat_make_guests_happy() +{ + int spriteIndex; + rct_peep *peep; + + FOR_ALL_GUESTS(spriteIndex, peep) + if (peep->var_2A == 0) + peep->happiness = 255; +} + +static void cheat_make_guests_nauseous() +{ + int spriteIndex; + rct_peep *peep; + + FOR_ALL_GUESTS(spriteIndex, peep) + peep->flags |= PEEP_FLAGS_NAUSEA; +} + +static void cheat_explode_guests() +{ + int sprite_index; + rct_peep *peep; + + FOR_ALL_GUESTS(sprite_index, peep) { + unsigned int rand = scenario_rand(); + if ((rand & 0x07) == 0) { + peep->flags |= PEEP_FLAGS_EXPLODE; + } + } + +} + +#pragma endregion + void window_cheats_open() { rct_window* window; @@ -264,14 +562,10 @@ void window_cheats_open() window->enabled_widgets = window_cheats_page_enabled_widgets[0]; window_init_scroll_widgets(window); window->page = WINDOW_CHEATS_PAGE_MONEY; - window->colours[0] = 1; - window->colours[1] = 19; - window->colours[2] = 19; } static void window_cheats_money_mouseup() { - int i; short widgetIndex; rct_window *w; @@ -284,25 +578,19 @@ static void window_cheats_money_mouseup() case WIDX_TAB_1: case WIDX_TAB_2: case WIDX_TAB_3: + case WIDX_TAB_4: window_cheats_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_HIGH_MONEY: - i = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32)); - - if (i < INT_MAX - CHEATS_MONEY_INCREMENT) { - i += CHEATS_MONEY_INCREMENT; - } - else { - i = INT_MAX; - } - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(i); - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + cheat_increase_money(CHEATS_MONEY_INCREMENT); + break; + case WIDX_CLEAR_LOAN: + cheat_clear_loan(); break; case WIDX_PARK_ENTRANCE_FEE: - RCT2_GLOBAL(0x13573E5, uint32) ^= 0x020; - if (!(RCT2_GLOBAL(0x13573E5, uint32) & 0x020) ) w->widgets[widgetIndex].image = 2762; - else w->widgets[widgetIndex].image = 2761; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_PARK_FREE_ENTRY; window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_RIDE); break; } } @@ -311,13 +599,9 @@ static void window_cheats_guests_mouseup() { short widgetIndex; rct_window *w; - int i; - + window_widget_get_registers(w, widgetIndex); - rct_peep* peep; - uint16 spriteIndex; - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -325,19 +609,20 @@ static void window_cheats_guests_mouseup() case WIDX_TAB_1: case WIDX_TAB_2: case WIDX_TAB_3: + case WIDX_TAB_4: window_cheats_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_HAPPY_GUESTS: - FOR_ALL_GUESTS(spriteIndex, peep) - if (peep->var_2A == 0) - peep->happiness = 255; - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + cheat_make_guests_happy(); break; case WIDX_TRAM_GUESTS: - for (i = 0; i < CHEATS_TRAM_INCREMENT; i++){ - generate_new_guest(); - } - window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + cheat_generate_guests(CHEATS_TRAM_INCREMENT); + break; + case WIDX_NAUSEA_GUESTS: + cheat_make_guests_nauseous(); + break; + case WIDX_EXPLODE_GUESTS: + cheat_explode_guests(); break; } } @@ -356,22 +641,15 @@ static void window_cheats_misc_mouseup() case WIDX_TAB_1: case WIDX_TAB_2: case WIDX_TAB_3: + case WIDX_TAB_4: window_cheats_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_FREEZE_CLIMATE: toggle_climate_lock(); - w->widgets[widgetIndex].image = w->widgets[widgetIndex].image == 2767 ? 2768 : 2767; + w->widgets[widgetIndex].image = w->widgets[widgetIndex].image == STR_CHEAT_FREEZE_CLIMATE ? STR_CHEAT_UNFREEZE_CLIMATE : STR_CHEAT_FREEZE_CLIMATE; break; case WIDX_OPEN_CLOSE_PARK: - game_do_command(0, 1, 0, park_is_open() ? 0 : 0x101, GAME_COMMAND_SET_PARK_OPEN, 0, 0); - w->widgets[widgetIndex].image = w->widgets[widgetIndex].image == 2769 ? 2770 : 2769; - window_invalidate_by_class(WC_PARK_INFORMATION); - break; - case WIDX_DECREASE_GAME_SPEED: - game_reduce_game_speed(); - break; - case WIDX_INCREASE_GAME_SPEED: - game_increase_game_speed(); + park_set_open(park_is_open() ? 0 : 1); break; case WIDX_ZERO_CLEARANCE: if (tool_set(w, widgetIndex, 7)) { @@ -384,6 +662,90 @@ static void window_cheats_misc_mouseup() case WIDX_WEATHER_THUNDER: climate_force_weather(WEATHER_THUNDER); break; + case WIDX_CLEAR_GRASS: + cheat_set_grass_length(GRASS_LENGTH_CLEAR_0); + break; + case WIDX_MOWED_GRASS: + cheat_set_grass_length(GRASS_LENGTH_MOWED); + break; + case WIDX_WATER_PLANTS: + cheat_water_plants(); + break; + case WIDX_FIX_VANDALISM: + cheat_fix_vandalism(); + break; + case WIDX_REMOVE_LITTER: + cheat_remove_litter(); + break; + case WIDX_WIN_SCENARIO: + scenario_success(); + break; + case WIDX_UNLOCK_ALL_PRICES: + gConfigCheat.unlock_all_prices ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_RIDE); + window_invalidate_by_class(WC_PARK_INFORMATION); + break; + case WIDX_SANDBOX_MODE: + gSandboxMode = !gSandboxMode; + w->widgets[widgetIndex].image = w->widgets[widgetIndex].image == STR_CHEAT_SANDBOX_MODE ? STR_CHEAT_SANDBOX_MODE_DISABLE : STR_CHEAT_SANDBOX_MODE; + // To prevent tools from staying active after disabling cheat + tool_cancel(); + window_invalidate_by_class(WC_MAP); + window_invalidate_by_class(WC_FOOTPATH); + break; + } +} + +static void window_cheats_rides_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + window_cheats_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_RENEW_RIDES: + cheat_renew_rides(); + break; + case WIDX_REMOVE_SIX_FLAGS: + cheat_remove_six_flags(); + break; + case WIDX_MAKE_DESTRUCTIBLE: + cheat_make_destructible(); + break; + case WIDX_FIX_ALL: + cheat_fix_rides(); + break; + case WIDX_FAST_LIFT_HILL: + gConfigCheat.fast_lift_hill ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_DISABLE_BRAKES_FAILURE: + gConfigCheat.disable_brakes_failure ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_DISABLE_ALL_BREAKDOWNS: + gConfigCheat.disable_all_breakdowns ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_BUILD_IN_PAUSE_MODE: + gConfigCheat.build_in_pause_mode ^= 1; + config_save_default(); + window_invalidate(w); } } @@ -399,8 +761,7 @@ static void window_cheats_invalidate() rct_window *w; window_get_register(w); - - strcpy((char*)0x009BC677, "Cheats"); + colour_scheme_update(w); rct_widget *widgets = window_cheats_page_widgets[w->page]; if (w->widgets != widgets) { @@ -408,6 +769,27 @@ static void window_cheats_invalidate() window_init_scroll_widgets(w); } + w->pressed_widgets = 0; + + switch (w->page) { + case WINDOW_CHEATS_PAGE_MONEY: + w->widgets[WIDX_PARK_ENTRANCE_FEE].image = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY ? + STR_CHEAT_PAY_ENTRANCE : STR_CHEAT_PAY_RIDES; + break; + case WINDOW_CHEATS_PAGE_MISC: + w->widgets[WIDX_OPEN_CLOSE_PARK].image = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN ? + STR_CHEAT_CLOSE_PARK : STR_CHEAT_OPEN_PARK; + widget_set_checkbox_value(w, WIDX_UNLOCK_ALL_PRICES, gConfigCheat.unlock_all_prices); + break; + case WINDOW_CHEATS_PAGE_RIDES: + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = 255; + widget_set_checkbox_value(w, WIDX_FAST_LIFT_HILL, gConfigCheat.fast_lift_hill); + widget_set_checkbox_value(w, WIDX_DISABLE_BRAKES_FAILURE, gConfigCheat.disable_brakes_failure); + widget_set_checkbox_value(w, WIDX_DISABLE_ALL_BREAKDOWNS, gConfigCheat.disable_all_breakdowns); + widget_set_checkbox_value(w, WIDX_BUILD_IN_PAUSE_MODE, gConfigCheat.build_in_pause_mode); + break; + } + // Set correct active tab for (i = 0; i < 7; i++) w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); @@ -425,27 +807,16 @@ static void window_cheats_paint() window_cheats_draw_tab_images(dpi, w); if (w->page == WINDOW_CHEATS_PAGE_MONEY){ - char buffer[256]; - // Format text - sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, "Increases your money by 5,000."); - // Draw shadow - gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(0) + TXTO); - - sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, "Toggle between Free and Paid Entry"); - // Draw shadow - gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(2) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_TIP_5K_MONEY, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(0) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_TIP_PAY_ENTRY, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(2) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_TIP_CLEAR_LOAN, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(4) + TXTO); } else if (w->page == WINDOW_CHEATS_PAGE_GUESTS){ - char buffer[256]; - // Format text - sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, "Increases every peeps happiness to max."); - // Draw shadow - gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(0) + TXTO); - - sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, "Large group of peeps arrive"); - gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(2) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_TIP_HAPPY_GUESTS, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(0) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_TIP_LARGE_TRAM_GUESTS, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(2) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_TIP_NAUSEA, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(4) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_TIP_EXPLODE, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(6) + TXTO); } - } static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) @@ -470,24 +841,36 @@ static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) // Misc tab if (!(w->disabled_widgets & (1 << WIDX_TAB_3))) { - sprite_idx = SPR_TAB_QUESTION; + sprite_idx = STR_TAB_PARK; gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TAB_3].left, w->y + w->widgets[WIDX_TAB_3].top, 0); } + + // Rides tab + if (!(w->disabled_widgets & (1 << WIDX_TAB_4))) { + sprite_idx = SPR_TAB_RIDE_0; + if (w->page == WINDOW_CHEATS_PAGE_RIDES) + sprite_idx += (w->frame_no / 4) % 16; + gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TAB_4].left, w->y + w->widgets[WIDX_TAB_4].top, 0); + } } static void window_cheats_set_page(rct_window *w, int page) { w->page = page; + w->frame_no = 0; w->enabled_widgets = window_cheats_page_enabled_widgets[page]; + w->pressed_widgets = 0; + w->event_handlers = window_cheats_page_events[page]; w->widgets = window_cheats_page_widgets[page]; window_invalidate(w); } -void window_cheats_misc_tool_update(){ +static void window_cheats_misc_tool_update() +{ short widgetIndex; rct_window* w; short x, y; @@ -496,27 +879,27 @@ void window_cheats_misc_tool_update(){ if (widgetIndex != WIDX_ZERO_CLEARANCE) return; - RCT2_CALLPROC_X(0x0068AAE1, x, y, 0, 0, (int)w, 0, 0); + map_invalidate_selection_rect(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); - int temp_y = y + 16; - int eax = x, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - RCT2_CALLFUNC_X(0x689726, &eax, &temp_y, &ecx, &edx, &esi, &edi, &ebp); - if (eax != 0x8000){ + int map_x, map_y; + footpath_get_coordinates_from_pos(x, y + 16, &map_x, &map_y, NULL, NULL); + if (map_x != (sint16)0x8000){ RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = temp_y; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = temp_y; - RCT2_CALLPROC_X(0x0068AAE1, eax, temp_y, 0, 0, (int)w, 0, 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = map_y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = map_y; + map_invalidate_selection_rect(); } RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; } -void window_cheats_misc_tool_down(){ +static void window_cheats_misc_tool_down() +{ short widgetIndex; rct_window* w; short x, y; @@ -525,30 +908,24 @@ void window_cheats_misc_tool_down(){ if (widgetIndex != WIDX_ZERO_CLEARANCE) return; - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - dest_y += 16; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + footpath_get_coordinates_from_pos(x, y + 16, &dest_x, &dest_y, NULL, NULL); - if (dest_x == 0x8000)return; + if (dest_x == (sint16)0x8000)return; // Set the coordinate of destination to be exactly // in the middle of a tile. dest_x += 16; dest_y += 16; + // Set the tile coordinate to top left of tile - int tile_y = dest_y & 0xFFE0; - int tile_x = dest_x & 0xFFE0; + int tile_x = (dest_x & 0xFFE0) >> 5; + int tile_y = (dest_y & 0xFFE0) >> 5; - ebp = ((tile_y << 8) | tile_x) >> 5; - - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(ebp); - - while (1){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_SURFACE){ - map_element->clearance_height = 0; + rct_map_element *mapElement = map_get_first_element_at(tile_x, tile_y); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SURFACE) { + mapElement->clearance_height = 0; } - if (map_element->flags & MAP_ELEMENT_FLAG_LAST_TILE) - break; - map_element++; - } -} \ No newline at end of file + } while (!map_element_is_last_for_tile(mapElement++)); +} diff --git a/src/windows/clear_scenery.c b/src/windows/clear_scenery.c index 9c5b514f56..88b2c670c7 100644 --- a/src/windows/clear_scenery.c +++ b/src/windows/clear_scenery.c @@ -25,6 +25,7 @@ #include "../sprites.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../interface/themes.h" enum WINDOW_CLEAR_SCENERY_WIDGET_IDX { WIDX_BACKGROUND, @@ -32,19 +33,26 @@ enum WINDOW_CLEAR_SCENERY_WIDGET_IDX { WIDX_CLOSE, WIDX_PREVIEW, WIDX_DECREMENT, - WIDX_INCREMENT + WIDX_INCREMENT, + WIDX_SMALL_SCENERY, + WIDX_LARGE_SCENERY, + WIDX_FOOTPATH }; rct_widget window_clear_scenery_widgets[] = { - { WWT_FRAME, 0, 0, 97, 0, 66, -1, STR_NONE }, // panel / background + { WWT_FRAME, 0, 0, 97, 0, 93, -1, STR_NONE }, // panel / background { WWT_CAPTION, 0, 1, 96, 1, 14, STR_CLEAR_SCENERY, STR_WINDOW_TITLE_TIP }, // title bar { WWT_CLOSEBOX, 0, 85, 95, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button { WWT_IMGBTN, 0, 27, 70, 17, 48, SPR_LAND_TOOL_SIZE_0, STR_NONE }, // preview box { WWT_TRNBTN, 1, 28, 43, 18, 33, 0x20000000 | SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_LAND_TIP }, // decrement size { WWT_TRNBTN, 1, 54, 69, 32, 47, 0x20000000 | SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_LAND_TIP }, // increment size + { WWT_FLATBTN, 1, 7, 30, 53, 76, 0x20000000 | SPR_G2_BUTTON_TREES, 5272 }, // small scenery + { WWT_FLATBTN, 1, 37, 60, 53, 76, 0x20000000 | SPR_G2_BUTTON_LARGE_SCENERY, 5273 }, // large scenery + { WWT_FLATBTN, 1, 67, 90, 53, 76, 0x20000000 | SPR_G2_BUTTON_FOOTPATH, 5274 }, // footpaths { WIDGETS_END }, }; + static int window_clear_scenery_should_close(); static void window_clear_scenery_emptysub() { } @@ -53,6 +61,8 @@ static void window_clear_scenery_mouseup(); static void window_clear_scenery_update(rct_window *w); static void window_clear_scenery_invalidate(); static void window_clear_scenery_paint(); +static void window_clear_scenery_textinput(); +static void window_clear_scenery_inputsize(rct_window *w); static void* window_clear_scenery_events[] = { window_clear_scenery_close, @@ -74,7 +84,7 @@ static void* window_clear_scenery_events[] = { window_clear_scenery_emptysub, window_clear_scenery_emptysub, window_clear_scenery_emptysub, - window_clear_scenery_emptysub, + window_clear_scenery_textinput, window_clear_scenery_emptysub, window_clear_scenery_emptysub, window_clear_scenery_emptysub, @@ -97,16 +107,18 @@ void window_clear_scenery_open() if (window_find_by_class(WC_CLEAR_SCENERY) != NULL) return; - window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 98, 29, 98, 67, (uint32*)window_clear_scenery_events, WC_CLEAR_SCENERY, 0); + window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 98, 29, 98, 94, (uint32*)window_clear_scenery_events, WC_CLEAR_SCENERY, 0); window->widgets = window_clear_scenery_widgets; - window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_INCREMENT) | (1 << WIDX_DECREMENT); + window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_INCREMENT) | (1 << WIDX_DECREMENT) | (1 << WIDX_PREVIEW) | + (1 << WIDX_SMALL_SCENERY) | (1 << WIDX_LARGE_SCENERY) | (1 << WIDX_FOOTPATH); window_init_scroll_widgets(window); window_push_others_below(window); - RCT2_GLOBAL(0x00F1AD62, uint32) = 0x80000000; - window->colours[0] = 24; - window->colours[1] = 24; - window->colours[2] = 24; + RCT2_GLOBAL(0x00F1AD62, uint32) = MONEY32_UNDEFINED; + + gClearSmallScenery = true; + gClearLargeScenery = false; + gClearFootpath = false; } /** @@ -161,9 +173,54 @@ static void window_clear_scenery_mouseup() // Invalidate the window window_invalidate(w); break; + case WIDX_PREVIEW: + window_clear_scenery_inputsize(w); + break; + case WIDX_SMALL_SCENERY: + gClearSmallScenery ^= 1; + window_invalidate(w); + break; + case WIDX_LARGE_SCENERY: + gClearLargeScenery ^= 1; + window_invalidate(w); + break; + case WIDX_FOOTPATH: + gClearFootpath ^= 1; + window_invalidate(w); + break; } } +static void window_clear_scenery_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + int size; + char* end; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (widgetIndex != WIDX_PREVIEW || !result) + return; + + size = strtol(text, &end, 10); + if (*end == '\0') { + if (size < 1) size = 1; + if (size > 7) size = 7; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = size; + window_invalidate(w); + } +} + +static void window_clear_scenery_inputsize(rct_window *w) +{ + ((uint16*)TextInputDescriptionArgs)[0] = 1; + ((uint16*)TextInputDescriptionArgs)[1] = 7; + window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); +} + /** * * rct2: 0x0068E205 @@ -184,9 +241,13 @@ static void window_clear_scenery_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); // Set the preview image button to be pressed down - w->pressed_widgets |= (1 << WIDX_PREVIEW); + w->pressed_widgets = (1 << WIDX_PREVIEW) | + (gClearSmallScenery ? (1 << WIDX_SMALL_SCENERY) : 0) | + (gClearLargeScenery ? (1 << WIDX_LARGE_SCENERY) : 0) | + (gClearFootpath ? (1 << WIDX_FOOTPATH) : 0); // Update the preview image window_clear_scenery_widgets[WIDX_PREVIEW].image = SPR_LAND_TOOL_SIZE_0 + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); @@ -208,8 +269,8 @@ static void window_clear_scenery_paint() // Draw cost amount x = (window_clear_scenery_widgets[WIDX_PREVIEW].left + window_clear_scenery_widgets[WIDX_PREVIEW].right) / 2 + w->x; - y = window_clear_scenery_widgets[WIDX_PREVIEW].bottom + w->y + 5; - if (RCT2_GLOBAL(0x00F1AD62, uint32) != 0x80000000 && RCT2_GLOBAL(0x00F1AD62, uint32) != 0) + y = window_clear_scenery_widgets[WIDX_PREVIEW].bottom + w->y + 5 + 27; + if (RCT2_GLOBAL(0x00F1AD62, uint32) != MONEY32_UNDEFINED && RCT2_GLOBAL(0x00F1AD62, uint32) != 0) gfx_draw_string_centred(dpi, 986, x, y, 0, (void*)0x00F1AD62); } diff --git a/src/windows/demolish_ride_prompt.c b/src/windows/demolish_ride_prompt.c index fc2d9aad4f..ba62515caf 100644 --- a/src/windows/demolish_ride_prompt.c +++ b/src/windows/demolish_ride_prompt.c @@ -27,6 +27,7 @@ #include "../peep/staff.h" #include "../sprites.h" #include "../world/sprite.h" +#include "../interface/themes.h" #define WW 200 #define WH 100 @@ -51,6 +52,7 @@ static rct_widget window_ride_demolish_widgets[] = { static void window_ride_demolish_emptysub(){} static void window_ride_demolish_mouseup(); +static void window_ride_demolish_invalidate(); static void window_ride_demolish_paint(); //0x0098E2E4 @@ -80,7 +82,7 @@ static void* window_ride_demolish_events[] = { window_ride_demolish_emptysub, window_ride_demolish_emptysub, window_ride_demolish_emptysub, - window_ride_demolish_emptysub, + window_ride_demolish_invalidate, window_ride_demolish_paint, window_ride_demolish_emptysub }; @@ -93,19 +95,11 @@ void window_ride_demolish_prompt_open(int rideIndex){ if (w != NULL) return; - // Find center of the screen. - int screen_height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); - int screen_width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - int x = screen_width / 2 - WW / 2; - int y = screen_height / 2 - WH / 2; - - w = window_create(x, y, WW, WH, (uint32*)window_ride_demolish_events, WC_DEMOLISH_RIDE_PROMPT, 0); + w = window_create_centred(WW, WH, (uint32*)window_ride_demolish_events, WC_DEMOLISH_RIDE_PROMPT, WF_TRANSPARENT); w->widgets = window_ride_demolish_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_CANCEL) | (1 << WIDX_DEMOLISH); window_init_scroll_widgets(w); - w->flags |= WF_TRANSPARENT; w->number = rideIndex; - w->colours[0] = 154; } @@ -130,6 +124,14 @@ static void window_ride_demolish_mouseup(){ } } +static void window_ride_demolish_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + /** * * rct2: 0x006B48E5 diff --git a/src/windows/dropdown.c b/src/windows/dropdown.c index a4cf76fc46..f8581cf490 100644 --- a/src/windows/dropdown.c +++ b/src/windows/dropdown.c @@ -54,6 +54,7 @@ uint16 gDropdownItemsFormat[64]; sint64 gDropdownItemsArgs[64]; // Replaces 0x009DED38 uint32 gDropdownItemsChecked; +uint32 *gDropdownItemsDisabled = RCT2_ADDRESS(0x009DED34, uint32); static void window_dropdown_emptysub() { } static void window_dropdown_paint(); @@ -136,9 +137,9 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo memcpy((void*)0x009DEBA4, gDropdownItemsFormat, 40 * 2); memcpy((void*)0x009DEBF4, gDropdownItemsArgs, 40 * 8); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_1 | INPUT_FLAG_2); - if (flags & 0x80) - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_1; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP); + if (flags & DROPDOWN_FLAG_STAY_OPEN) + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_DROPDOWN_STAY_OPEN; window_dropdown_close(); _dropdown_num_columns = 1; @@ -150,6 +151,14 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo // Set the widgets gDropdownNumItems = num_items; _dropdown_num_rows = num_items; + + width = _dropdown_item_width * _dropdown_num_columns + 3; + int height = _dropdown_item_height * _dropdown_num_rows + 3; + if (x + width > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)) + x = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - width); + if (y + height > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)) + y = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - height); + window_dropdown_widgets[WIDX_BACKGROUND].bottom = _dropdown_item_height * num_items + 3; window_dropdown_widgets[WIDX_BACKGROUND].right = _dropdown_item_width + 3; @@ -205,9 +214,9 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl memcpy((void*)0x009DEBA4, gDropdownItemsFormat, 40 * 2); memcpy((void*)0x009DEBF4, gDropdownItemsArgs, 40 * 8); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_1 | INPUT_FLAG_2); - if (flags & 0x80) - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_1; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP); + if (flags & DROPDOWN_FLAG_STAY_OPEN) + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_DROPDOWN_STAY_OPEN; // Close existing dropdown window_dropdown_close(); @@ -403,19 +412,6 @@ void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, ui if (availableColours & (1 << i)) numItems++; - // Show dropdown - window_dropdown_show_image( - w->x + widget->left, - w->y + widget->top, - widget->bottom - widget->top + 1, - dropdownColour, - 0x80, - numItems, - 12, - 12, - gAppropriateImageDropdownItemsPerRow[numItems] - ); - // Set items for (i = 0; i < 32; i++) { if (availableColours & (1 << i)) { @@ -426,4 +422,18 @@ void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, ui gDropdownItemsArgs[i] = ((uint64)i << 32) | (0x20000000 | (i << 19) | 5059); } } + + // Show dropdown + window_dropdown_show_image( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + dropdownColour, + DROPDOWN_FLAG_STAY_OPEN, + numItems, + 12, + 12, + gAppropriateImageDropdownItemsPerRow[numItems] + ); + } diff --git a/src/windows/dropdown.h b/src/windows/dropdown.h index 76370cd212..c26f140197 100644 --- a/src/windows/dropdown.h +++ b/src/windows/dropdown.h @@ -25,12 +25,18 @@ #define DROPDOWN_SEPARATOR 0 +enum +{ + DROPDOWN_FLAG_STAY_OPEN = (1 << 7) +}; + extern int gAppropriateImageDropdownItemsPerRow[]; extern int gDropdownNumItems; extern uint16 gDropdownItemsFormat[64]; extern sint64 gDropdownItemsArgs[64]; extern uint32 gDropdownItemsChecked; +extern uint32 *gDropdownItemsDisabled; void window_dropdown_show_text(int x, int y, int extray, uint8 colour, uint8 flags, int num_items); void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colour, uint8 flags, int num_items, int width); diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c index 8cce5e0074..6f235769bf 100644 --- a/src/windows/editor_bottom_toolbar.c +++ b/src/windows/editor_bottom_toolbar.c @@ -28,12 +28,14 @@ #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" -#include "../platform/osinterface.h" +#include "../platform/platform.h" #include "../title.h" #include "../util/util.h" +#include "../world/scenery.h" #include "error.h" +#include "../interface/themes.h" -enum WINDOW_EDITOR_TOP_TOOLBAR_WIDGET_IDX { +enum { WIDX_PREVIOUS_IMAGE, // 1 WIDX_PREVIOUS_STEP_BUTTON, // 2 WIDX_NEXT_IMAGE, // 4 @@ -139,15 +141,6 @@ void window_editor_bottom_toolbar_open() (1 << WIDX_NEXT_IMAGE); window_init_scroll_widgets(window); - window->colours[0] = 150; - window->colours[1] = 150; - window->colours[2] = 141; - - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { - window->colours[0] = 135; - window->colours[1] = 135; - window->colours[2] = 135; - } } /** @@ -166,8 +159,8 @@ void window_editor_bottom_toolbar_jump_back_to_object_selection() { */ void window_editor_bottom_toolbar_jump_back_to_landscape_editor() { window_close_all(); - RCT2_CALLPROC(0x006DFED0); - RCT2_CALLPROC(0x006DFEE4); + RCT2_CALLPROC_EBPSAFE(0x006DFED0); + scenery_set_default_placement_configuration(); g_editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; window_map_open(); gfx_invalidate_screen(); @@ -179,7 +172,7 @@ void window_editor_bottom_toolbar_jump_back_to_landscape_editor() { */ void window_editor_bottom_toolbar_jump_back_to_invention_list_set_up() { window_close_all(); - RCT2_CALLPROC_EBPSAFE(0x00684E04); // open invention list window + window_editor_inventions_list_open(); g_editor_step = EDITOR_STEP_INVENTIONS_LIST_SET_UP; gfx_invalidate_screen(); } @@ -190,7 +183,7 @@ void window_editor_bottom_toolbar_jump_back_to_invention_list_set_up() { */ void window_editor_bottom_toolbar_jump_back_to_scenario_options() { window_close_all(); - RCT2_CALLPROC_EBPSAFE(0x00670138); // open scenario options + window_editor_scenario_options_open(); g_editor_step = EDITOR_STEP_OPTIONS_SELECTION; gfx_invalidate_screen(); } @@ -201,17 +194,38 @@ void window_editor_bottom_toolbar_jump_back_to_scenario_options() { */ void window_editor_bottom_toolbar_jump_back_to_options_selection() { window_close_all(); - RCT2_CALLPROC_EBPSAFE(0x00670138); // open options selection window + window_editor_scenario_options_open(); g_editor_step = EDITOR_STEP_OPTIONS_SELECTION; gfx_invalidate_screen(); } /** -* -* rct2: 0x0066F6B0 -*/ -void window_editor_bottom_toolbar_jump_forward_from_object_selection() { - RCT2_CALLPROC_EBPSAFE(0x0066f6b0); + * + * rct2: 0x006AB1CE + */ +int window_editor_bottom_toolbar_check_object_selection() +{ + return RCT2_CALLPROC_EBPSAFE(0x006AB1CE) & 0x100; +} + +/** + * + * rct2: 0x0066F6B0 + */ +void window_editor_bottom_toolbar_jump_forward_from_object_selection() +{ + if (window_editor_bottom_toolbar_check_object_selection()) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) { + RCT2_CALLPROC_EBPSAFE(0x0066F6E3); + } else { + RCT2_CALLPROC_EBPSAFE(0x006DFED0); + scenery_set_default_placement_configuration(); + RCT2_GLOBAL(0x00141F570, uint8) = 1; + window_map_open(); + gfx_invalidate_screen(); + } } /** @@ -223,7 +237,7 @@ void window_editor_bottom_toolbar_jump_forward_to_invention_list_set_up() { if (!(flags & 0x100)) { window_close_all(); - RCT2_CALLPROC_EBPSAFE(0x00684E04); + window_editor_inventions_list_open(); g_editor_step = EDITOR_STEP_INVENTIONS_LIST_SET_UP; } else { window_error_open(STR_CANT_ADVANCE_TO_NEXT_EDITOR_STAGE, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16)); @@ -238,7 +252,7 @@ void window_editor_bottom_toolbar_jump_forward_to_invention_list_set_up() { */ void window_editor_bottom_toolbar_jump_forward_to_options_selection() { window_close_all(); - RCT2_CALLPROC_EBPSAFE(0x00670138); + window_editor_scenario_options_open(); g_editor_step = EDITOR_STEP_OPTIONS_SELECTION; gfx_invalidate_screen(); } @@ -249,7 +263,7 @@ void window_editor_bottom_toolbar_jump_forward_to_options_selection() { */ void window_editor_bottom_toolbar_jump_forward_to_objective_selection() { window_close_all(); - RCT2_CALLPROC_EBPSAFE(0x0067137D); + window_editor_objective_options_open(); g_editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; gfx_invalidate_screen(); } @@ -274,7 +288,7 @@ static int show_save_scenario_dialog(char *resultPath) format_string(filterName, STR_RCT2_SCENARIO_FILE, NULL); pause_sounds(); - result = osinterface_open_common_file_dialog(0, title, filename, "*.SC6", filterName); + result = platform_open_common_file_dialog(0, title, filename, "*.SC6", filterName); unpause_sounds(); if (result) @@ -299,6 +313,10 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario() } window_close_all(); + + window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO, s6Info->name); + return; + if (!show_save_scenario_dialog(path)) { gfx_invalidate_screen(); return; @@ -313,11 +331,10 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario() // Save the scenario parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18; - success = scenario_save(path, gGeneral_config.save_plugin_data ? 3 : 2); + success = scenario_save(path, gConfigGeneral.save_plugin_data ? 3 : 2); RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; if (success) { - // RCT2_CALLPROC_EBPSAFE(0x0066DC83); title_load(); } else { window_error_open(STR_SCENARIO_SAVE_FAILED, -1); @@ -338,7 +355,7 @@ static void window_editor_bottom_toolbar_mouseup() if (widgetIndex == WIDX_PREVIOUS_STEP_BUTTON) { if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) || - RCT2_GLOBAL(0x13573C8, uint16) == 0x2710 && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO)) { + RCT2_GLOBAL(0x13573C8, uint16) == 0x2710 && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_18)) { previous_button_mouseup_events[g_editor_step](); } } else if (widgetIndex == WIDX_NEXT_STEP_BUTTON) { @@ -365,11 +382,13 @@ void window_editor_bottom_toolbar_invalidate() { window_get_register(w); + colour_scheme_update_by_class(w, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) ? WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR : WC_EDITOR_TRACK_BOTTOM_TOOLBAR); + sint16 screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].left = screenWidth - 198; - window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].right = screenWidth - 3; - window_editor_bottom_toolbar_widgets[WIDX_NEXT_STEP_BUTTON].left = screenWidth - 200; - window_editor_bottom_toolbar_widgets[WIDX_NEXT_STEP_BUTTON].right = screenWidth - 1; + window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].left = screenWidth - 200; + window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].right = screenWidth - 1; + window_editor_bottom_toolbar_widgets[WIDX_NEXT_STEP_BUTTON].left = screenWidth - 198; + window_editor_bottom_toolbar_widgets[WIDX_NEXT_STEP_BUTTON].right = screenWidth - 3; window_editor_bottom_toolbar_widgets[WIDX_PREVIOUS_STEP_BUTTON].type = WWT_FLATBTN; window_editor_bottom_toolbar_widgets[WIDX_NEXT_STEP_BUTTON].type = WWT_FLATBTN; @@ -385,7 +404,7 @@ void window_editor_bottom_toolbar_invalidate() { } else if (g_editor_step == EDITOR_STEP_ROLLERCOASTER_DESIGNER) { hide_next_step_button(); } else if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER)) { - if (RCT2_GLOBAL(0x13573C8, uint16) != 0x2710 || RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + if (RCT2_GLOBAL(0x13573C8, uint16) != 0x2710 || RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_18) { hide_previous_step_button(); } } @@ -407,13 +426,17 @@ void window_editor_bottom_toolbar_paint() { if (g_editor_step == EDITOR_STEP_OBJECT_SELECTION) { drawNextButton = true; - } else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) { + } + else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) { drawPreviousButton = true; - } else if (RCT2_GLOBAL(0x13573C8, uint16) != 0x2710) { + } + else if (RCT2_GLOBAL(0x13573C8, uint16) != 0x2710) { drawNextButton = true; - } else if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + } + else if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_18) { drawNextButton = true; - } else { + } + else { drawPreviousButton = true; } diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index a2353dbc0c..de90fbf90b 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -19,6 +19,500 @@ *****************************************************************************/ #include "../addresses.h" +#include "../cursors.h" +#include "../input.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../management/research.h" +#include "../object.h" +#include "../world/scenery.h" +#include "../interface/themes.h" + +#pragma region Widgets + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PAGE_BACKGROUND, + WIDX_TAB_1, + WIDX_PRE_RESEARCHED_SCROLL, + WIDX_RESEARCH_ORDER_SCROLL, + WIDX_PREVIEW, + WIDX_RANDOM_SHUFFLE, + WIDX_MOVE_ITEMS_TO_BOTTOM, + WIDX_MOVE_ITEMS_TO_TOP +}; + +static rct_widget window_editor_inventions_list_widgets[] = { + { WWT_FRAME, 0, 0, 599, 0, 399, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 598, 1, 14, STR_INVENTION_LIST, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 587, 597, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 599, 43, 399, STR_NONE, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_NONE }, + { WWT_SCROLL, 1, 4, 371, 56, 175, 2, STR_NONE }, + { WWT_SCROLL, 1, 4, 371, 189, 396, 2, STR_NONE }, + { WWT_FLATBTN, 1, 431, 544, 106, 219, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 375, 594, 385, 396, STR_RANDOM_SHUFFLE, STR_RANDOM_SHUFFLE_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 375, 594, 372, 383, 2751, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 375, 594, 359, 370, 2750, STR_NONE }, + { WIDGETS_END } +}; + +static rct_widget window_editor_inventions_list_drag_widgets[] = { + { WWT_IMGBTN, 0, 0, 149, 0, 13, STR_NONE, STR_NONE }, + { WIDGETS_END } +}; + +#pragma endregion + +#pragma region Events + +static void window_editor_inventions_list_emptysub() { } + +static void window_editor_inventions_list_close(); +static void window_editor_inventions_list_mouseup(); +static void window_editor_inventions_list_update(rct_window *w); +static void window_editor_inventions_list_scrollgetheight(); +static void window_editor_inventions_list_scrollmousedown(); +static void window_editor_inventions_list_scrollmouseover(); +static void window_editor_inventions_list_tooltip(); +static void window_editor_inventions_list_cursor(); +static void window_editor_inventions_list_invalidate(); +static void window_editor_inventions_list_paint(); +static void window_editor_inventions_list_scrollpaint(); + +static void window_editor_inventions_list_drag_cursor(); +static void window_editor_inventions_list_drag_moved(); +static void window_editor_inventions_list_drag_paint(); + +// 0x0098177C +static void* window_editor_inventions_list_events[] = { + window_editor_inventions_list_close, + window_editor_inventions_list_mouseup, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_update, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_scrollgetheight, + window_editor_inventions_list_scrollmousedown, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_scrollmouseover, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_tooltip, + window_editor_inventions_list_cursor, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_invalidate, + window_editor_inventions_list_paint, + window_editor_inventions_list_scrollpaint +}; + +// 0x009817EC +static void* window_editor_inventions_list_drag_events[] = { + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_drag_cursor, + window_editor_inventions_list_drag_moved, + window_editor_inventions_list_emptysub, + window_editor_inventions_list_drag_paint, + window_editor_inventions_list_emptysub +}; + +#pragma endregion + +rct_research_item *_editorInventionsListDraggedItem; + +#define WindowHighlightedItem(w) *((rct_research_item**)&(w->var_494)) + +static void window_editor_inventions_list_drag_open(rct_research_item *researchItem); +static void move_research_item(rct_research_item *beforeItem); + +static int research_item_is_always_researched(rct_research_item *researchItem) +{ + return (researchItem->entryIndex & (RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED | RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED)) != 0; +} + +/* rct2: 0x0068596F + * Sets rides that are in use to be always researched + */ +static void research_rides_setup(){ + // Reset all objects to not required + for (uint8 object_type = OBJECT_TYPE_RIDE; object_type < 11; object_type++){ + uint8* in_use = RCT2_ADDRESS(0x0098DA38, uint8*)[object_type]; + for (uint8 num_objects = object_entry_group_counts[object_type]; num_objects != 0; num_objects--){ + *in_use++ = 0; + } + } + + // Set research required for rides in use + for (uint16 rideIndex = 0; rideIndex < 255; rideIndex++){ + rct_ride* ride = &g_ride_list[rideIndex]; + if (ride->type == RIDE_TYPE_NULL)continue; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_RIDE][ride->subtype] |= 1; + } + + for (rct_research_item* research = gResearchItems; research->entryIndex != RESEARCHED_ITEMS_END; research++){ + if (research->entryIndex & RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED) + continue; + + // If not a ride + if ((research->entryIndex & 0xFFFFFF) < 0x10000) + continue; + + uint8 ride_base_type = (research->entryIndex >> 8) & 0xFF; + + uint8 object_index = research->entryIndex & 0xFF; + rct_ride_type* ride_entry = GET_RIDE_ENTRY(object_index); + + uint8 master_found = 0; + if (!(ride_entry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE)){ + + for (uint8 rideType = 0; rideType < object_entry_group_counts[OBJECT_TYPE_RIDE]; rideType++){ + rct_ride_type* master_ride = GET_RIDE_ENTRY(rideType); + if (master_ride == NULL || (uint32)master_ride == 0xFFFFFFFF) + continue; + + if (master_ride->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE) + continue; + + // If master ride not in use + if (!(RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_RIDE][rideType] & (1 << 0))) + continue; + + if (ride_base_type == master_ride->ride_type[0] || + ride_base_type == master_ride->ride_type[1] || + ride_base_type == master_ride->ride_type[2]){ + master_found = 1; + break; + } + } + } + + if (!master_found){ + // If not in use + if (!(RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_RIDE][object_index] & (1 << 0))) + continue; + if (ride_base_type != ride_entry->ride_type[0] && + ride_base_type != ride_entry->ride_type[1] && + ride_base_type != ride_entry->ride_type[2]){ + continue; + } + } + + research->entryIndex |= RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED; + _editorInventionsListDraggedItem = research; + move_research_item(gResearchItems); + _editorInventionsListDraggedItem = NULL; + research--; + } +} + +/* rct2: 0x0068590C + * Sets the critical scenery sets to always researched + */ +static void research_scenery_sets_setup(){ + + for (rct_object_entry* object = RCT2_ADDRESS(0x0098DA74, rct_object_entry); + (object->flags & 0xFF) != 0xFF; + object++){ + + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(object, &entry_type, &entry_index)) + continue; + + if (entry_type != OBJECT_TYPE_SCENERY_SETS) + continue; + + rct_research_item* research = gResearchItems; + for (; research->entryIndex != RESEARCHED_ITEMS_END; research++){ + + if ((research->entryIndex & 0xFFFFFF) != entry_index) + continue; + + research->entryIndex |= RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED; + _editorInventionsListDraggedItem = research; + move_research_item(gResearchItems); + _editorInventionsListDraggedItem = NULL; + } + } +} + +/** + * + * rct2: 0x00685901 + */ +static void research_always_researched_setup() +{ + research_rides_setup(); + research_scenery_sets_setup(); +} + +/** + * + * rct2: 0x00685A79 + */ +static void sub_685A79() +{ + for (rct_research_item* research = gResearchItems; + research->entryIndex != RESEARCHED_ITEMS_END_2; + research++){ + + // Clear the always researched flags. + if (research->entryIndex > RESEARCHED_ITEMS_SEPERATOR){ + research->entryIndex &= 0x00FFFFFF; + } + } +} + +/** + * + * rct2: 0x0068563D + */ +static rct_string_id research_item_get_name(uint32 researchItem) +{ + rct_ride_type *rideEntry; + rct_scenery_set_entry *sceneryEntry; + + if (researchItem < 0x10000) { + sceneryEntry = g_scenerySetEntries[researchItem & 0xFF]; + if (sceneryEntry == NULL || sceneryEntry == (rct_scenery_set_entry*)0xFFFFFFFF) + return 0; + + return sceneryEntry->name; + } + + rideEntry = GET_RIDE_ENTRY(researchItem & 0xFF); + if (rideEntry == NULL || rideEntry == (rct_ride_type*)0xFFFFFFFF) + return 0; + + if (rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME) + return rideEntry->name; + + return ((researchItem >> 8) & 0xFF) + 2; +} + +/** + * + * rct2: 0x00685A93 + */ +static void research_items_shuffle() +{ + rct_research_item *researchItem, *researchOrderBase, researchItemTemp; + int i, ri, numNonResearchedItems; + + // Skip pre-researched items + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) {} + researchItem++; + researchOrderBase = researchItem; + + // Count non pre-researched items + numNonResearchedItems = 0; + for (; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) + numNonResearchedItems++; + + // Shuffle list + for (i = 0; i < numNonResearchedItems; i++) { + ri = rand() % numNonResearchedItems; + if (ri == i) + continue; + + researchItemTemp = researchOrderBase[i]; + researchOrderBase[i] = researchOrderBase[ri]; + researchOrderBase[ri] = researchItemTemp; + } +} + +static void research_items_make_all_unresearched() +{ + rct_research_item *researchItem, *nextResearchItem, researchItemTemp; + + int sorted; + do { + sorted = 1; + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { + if (research_item_is_always_researched(researchItem)) + continue; + + nextResearchItem = researchItem + 1; + if (nextResearchItem->entryIndex == RESEARCHED_ITEMS_SEPERATOR || research_item_is_always_researched(nextResearchItem)) { + // Bubble up always researched item or seperator + researchItemTemp = *researchItem; + *researchItem = *nextResearchItem; + *nextResearchItem = researchItemTemp; + sorted = 0; + + if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPERATOR) + break; + } + } + } while (!sorted); +} + +static void research_items_make_all_researched() +{ + rct_research_item *researchItem, researchItemTemp; + + // Find seperator + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + + // Move seperator below all items + for (; (researchItem + 1)->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { + // Swap seperator with research item + researchItemTemp = *researchItem; + *researchItem = *(researchItem + 1); + *(researchItem + 1) = researchItemTemp; + } +} + +/** + * + * rct2: 0x006855E7 + */ +static void move_research_item(rct_research_item *beforeItem) +{ + rct_window *w; + rct_research_item *researchItem, draggedItem; + + if (_editorInventionsListDraggedItem == beforeItem - 1) + return; + + // Back up the dragged item + draggedItem = *_editorInventionsListDraggedItem; + + // Remove dragged item from list + researchItem = _editorInventionsListDraggedItem; + do { + *researchItem = *(researchItem + 1); + researchItem++; + } while (researchItem->entryIndex != RESEARCHED_ITEMS_END_2); + // At end of this researchItem points to the end of the list + + if (beforeItem > _editorInventionsListDraggedItem) + beforeItem--; + + // Add dragged item to list + do { + *researchItem = *(researchItem - 1); + researchItem--; + } while (researchItem != beforeItem); + + *researchItem = draggedItem; + + w = window_find_by_class(WC_EDITOR_INVENTION_LIST); + if (w != NULL) { + WindowHighlightedItem(w) = NULL; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x0068558E + */ +static rct_research_item *window_editor_inventions_list_get_item_from_scroll_y(int scrollIndex, int y) +{ + rct_research_item *researchItem; + + researchItem = gResearchItems; + + if (scrollIndex != 0) { + // Skip pre-researched items + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + researchItem++; + } + + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR && researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { + y -= 10; + if (y < 0) + return researchItem; + } + + return NULL; +} + +/** + * + * rct2: 0x006855BB + */ +static rct_research_item *window_editor_inventions_list_get_item_from_scroll_y_include_seps(int scrollIndex, int y) +{ + rct_research_item *researchItem; + + researchItem = gResearchItems; + + if (scrollIndex != 0) { + // Skip pre-researched items + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + researchItem++; + } + + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR && researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { + y -= 10; + if (y < 0) + return researchItem; + } + + return researchItem; +} + +static rct_research_item *get_research_item_at(int x, int y) +{ + rct_window *w; + rct_widget *widget; + int scrollY, outX, outY, outScrollArea, outScrollId; + short widgetIndex; + + w = window_find_by_class(WC_EDITOR_INVENTION_LIST); + if (w != NULL && w->x <= x && w->y < y && w->x + w->width > x && w->y + w->height > y) { + widgetIndex = window_find_widget_from_point(w, x, y); + widget = &w->widgets[widgetIndex]; + if (widgetIndex == WIDX_PRE_RESEARCHED_SCROLL || widgetIndex == WIDX_RESEARCH_ORDER_SCROLL) { + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32) = widgetIndex; + widget_scroll_get_part(w, widget, x, y, &outX, &outY, &outScrollArea, &outScrollId); + if (outScrollArea == SCROLL_PART_VIEW) { + outScrollId = outScrollId == 0 ? 0 : 1; + + scrollY = y - (w->y + widget->top) + w->scrolls[outScrollId].v_top + 5; + return window_editor_inventions_list_get_item_from_scroll_y_include_seps(outScrollId, scrollY); + } + } + } + + return NULL; +} /** * @@ -26,5 +520,504 @@ */ void window_editor_inventions_list_open() { - RCT2_CALLPROC_EBPSAFE(0x00684E04); -} \ No newline at end of file + rct_window *w; + + w = window_bring_to_front_by_class(WC_EDITOR_INVENTION_LIST); + if (w != NULL) + return; + + research_always_researched_setup(); + + w = window_create_centred( + 600, + 400, + (uint32*)window_editor_inventions_list_events, + WC_EDITOR_INVENTION_LIST, + WF_2 + ); + w->widgets = window_editor_inventions_list_widgets; + w->enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_RANDOM_SHUFFLE) | + (1 << WIDX_MOVE_ITEMS_TO_BOTTOM) | + (1 << WIDX_MOVE_ITEMS_TO_TOP); + window_init_scroll_widgets(w); + w->var_4AE = 0; + w->selected_tab = 0; + WindowHighlightedItem(w) = NULL; + _editorInventionsListDraggedItem = NULL; +} + +/** + * + * rct2: 0x006853D2 + */ +static void window_editor_inventions_list_close() +{ + sub_685A79(); +} + +/** + * + * rct2: 0x0068521B + */ +static void window_editor_inventions_list_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_RANDOM_SHUFFLE: + research_items_shuffle(); + window_invalidate(w); + break; + case WIDX_MOVE_ITEMS_TO_TOP: + research_items_make_all_researched(); + window_init_scroll_widgets(w); + window_invalidate(w); + break; + case WIDX_MOVE_ITEMS_TO_BOTTOM: + research_items_make_all_unresearched(); + window_init_scroll_widgets(w); + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x00685392 + */ +static void window_editor_inventions_list_update(rct_window *w) +{ + w->frame_no++; + window_event_invalidate_call(w); + widget_invalidate(w, WIDX_TAB_1); + + if (_editorInventionsListDraggedItem == NULL) + return; + + if (window_find_by_class(WC_EDITOR_INVENTION_LIST_DRAG) != NULL) + return; + + _editorInventionsListDraggedItem = NULL; + window_invalidate(w); +} + +/** + * + * rct2: 0x00685239 + */ +static void window_editor_inventions_list_scrollgetheight() +{ + rct_window *w; + short scrollIndex; + rct_research_item *researchItem; + int width, height; + + window_scroll_get_registers(w, scrollIndex); + + width = 0; + height = 0; + + // Count / skip pre-researched items + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) + height += 10; + + if (scrollIndex == 1) { + researchItem++; + + // Count non pre-researched items + height = 0; + for (; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) + height += 10; + } + + window_scrollsize_set_registers(width, height); +} + +/** + * + * rct2: 0x006852D4 + */ +static void window_editor_inventions_list_scrollmousedown() +{ + rct_window *w; + rct_research_item *researchItem; + short scrollIndex, x, y; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + researchItem = window_editor_inventions_list_get_item_from_scroll_y(scrollIndex, y); + if (researchItem == NULL) + return; + + if (researchItem->entryIndex < (uint32)RESEARCHED_ITEMS_END_2 && research_item_is_always_researched(researchItem)) + return; + + window_invalidate(w); + window_editor_inventions_list_drag_open(researchItem); +} + +/** + * + * rct2: 0x00685275 + */ +static void window_editor_inventions_list_scrollmouseover() +{ + rct_window *w; + short scrollIndex, x, y; + rct_research_item *researchItem; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + researchItem = window_editor_inventions_list_get_item_from_scroll_y(scrollIndex, y); + if (researchItem != WindowHighlightedItem(w)) { + WindowHighlightedItem(w) = researchItem; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x0068526B + */ +static void window_editor_inventions_list_tooltip() +{ + RCT2_GLOBAL(0x013CE952, uint16) = 3159; +} + +/** + * + * rct2: 0x00685291 + */ +static void window_editor_inventions_list_cursor() +{ + rct_window *w; + rct_research_item *researchItem; + short widgetIndex, x, y; + int scrollIndex, cursorId; + + window_cursor_get_registers(w, widgetIndex, x, y); + + if (widgetIndex == WIDX_PRE_RESEARCHED_SCROLL) { + scrollIndex = 0; + } else if (widgetIndex == WIDX_RESEARCH_ORDER_SCROLL) { + scrollIndex = 1; + } else { + cursorId = -1; + window_cursor_set_registers(cursorId); + return; + } + + researchItem = window_editor_inventions_list_get_item_from_scroll_y(scrollIndex, y); + if (researchItem == NULL) + return; + + if (researchItem->entryIndex < (uint32)RESEARCHED_ITEMS_END_2 && research_item_is_always_researched(researchItem)) { + cursorId = -1; + window_cursor_set_registers(cursorId); + return; + } + + cursorId = CURSOR_HAND_OPEN; + window_cursor_set_registers(cursorId); +} + +/** + * + * rct2: 0x00685392 + */ +static void window_editor_inventions_list_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); + + w->pressed_widgets |= 1 << WIDX_PREVIEW; + w->pressed_widgets |= 1 << WIDX_TAB_1; + + w->widgets[WIDX_CLOSE].type = + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR ? WWT_EMPTY : WWT_CLOSEBOX; +} + +/** + * + * rct2: 0x00684EE0 + */ +static void window_editor_inventions_list_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_widget *widget; + rct_research_item *researchItem; + rct_string_id stringId; + int x, y, width; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + // Tab image + x = w->x + w->widgets[WIDX_TAB_1].left; + y = w->y + w->widgets[WIDX_TAB_1].top; + gfx_draw_sprite(dpi, 5327 + (w->frame_no / 2) % 8, x, y, 0); + + // Pre-researched items label + x = w->x + w->widgets[WIDX_PRE_RESEARCHED_SCROLL].left; + y = w->y + w->widgets[WIDX_PRE_RESEARCHED_SCROLL].top - 11; + gfx_draw_string_left(dpi, 3197, NULL, 0, x, y - 1); + + // Research order label + x = w->x + w->widgets[WIDX_RESEARCH_ORDER_SCROLL].left; + y = w->y + w->widgets[WIDX_RESEARCH_ORDER_SCROLL].top - 11; + gfx_draw_string_left(dpi, 3198, NULL, 0, x, y - 1); + + // Preview background + widget = &w->widgets[WIDX_PREVIEW]; + gfx_fill_rect( + dpi, + w->x + widget->left + 1, + w->y + widget->top + 1, + w->x + widget->right - 1, + w->y + widget->bottom - 1, + RCT2_GLOBAL(0x0141FC44 + (w->colours[1] * 8), uint8) + ); + + researchItem = _editorInventionsListDraggedItem; + if (researchItem == NULL) + researchItem = WindowHighlightedItem(w); + // If the research item is null or a list seperator. + if (researchItem == NULL || researchItem->entryIndex < 0) + return; + + // Preview image + x = w->x + ((widget->left + widget->right) / 2) + 1; + y = w->y + ((widget->top + widget->bottom) / 2) + 1; + + int objectEntryType = 7; + int eax = researchItem->entryIndex & 0xFFFFFF; + if (eax >= 0x10000) + objectEntryType = 0; + + void *chunk = object_entry_groups[objectEntryType].chunks[researchItem->entryIndex & 0xFF]; + + if (chunk == NULL || chunk == (void*)0xFFFFFFFF) + return; + + object_paint(objectEntryType, 3, objectEntryType, x, y, 0, (int)dpi, (int)chunk); + + // Item name + x = w->x + ((widget->left + widget->right) / 2) + 1; + y = w->y + widget->bottom + 3; + width = w->width - w->widgets[WIDX_RESEARCH_ORDER_SCROLL].right - 6; + stringId = research_item_get_name(eax); + gfx_draw_string_centred_clipped(dpi, 1193, &stringId, 0, x, y, width); + y += 15; + + // Item category + x = w->x + w->widgets[WIDX_RESEARCH_ORDER_SCROLL].right + 4; + stringId = 2253 + researchItem->category; + gfx_draw_string_left(dpi, 3196, &stringId, 0, x, y); +} + +/** + * + * rct2: 0x006850BD + */ +static void window_editor_inventions_list_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + short scrollIndex; + uint32 colour; + rct_research_item *researchItem; + int left, top, bottom, itemY, disableItemMovement; + sint32 researchItemEndMarker; + rct_string_id stringId; + char buffer[256], *ptr; + + window_scrollpaint_get_registers(w, dpi, scrollIndex); + + // Draw background + colour = RCT2_GLOBAL(0x0141FC48 + (w->colours[1] * 8), uint8); + colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; + gfx_clear(dpi, colour); + + researchItem = gResearchItems; + + if (scrollIndex == 1) { + // Skip pre-researched items + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + researchItem++; + researchItemEndMarker = RESEARCHED_ITEMS_END; + } else { + researchItemEndMarker = RESEARCHED_ITEMS_SEPERATOR; + } + + // Since this is now a do while need to conteract the +10 + itemY = -10; + do{ + itemY += 10; + if (itemY + 10 < dpi->y || itemY >= dpi->y + dpi->height) + continue; + + colour = 142; + if (WindowHighlightedItem(w) == researchItem) { + if (_editorInventionsListDraggedItem == NULL) { + // Highlight + top = itemY; + bottom = itemY + 9; + } else { + // Drop horizontal rule + top = itemY - 1; + bottom = itemY; + } + gfx_fill_rect(dpi, 0, top, w->width, bottom, 0x2000031); + + if (_editorInventionsListDraggedItem == NULL) + colour = 14; + } + + if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPERATOR || researchItem->entryIndex == RESEARCHED_ITEMS_END) + continue; + + if (researchItem == _editorInventionsListDraggedItem) + continue; + + disableItemMovement = research_item_is_always_researched(researchItem); + stringId = research_item_get_name(researchItem->entryIndex & 0xFFFFFF); + + ptr = buffer; + if (!disableItemMovement) + *ptr++ = colour & 0xFF; + + format_string(ptr, stringId, NULL); + + if (disableItemMovement) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = -1; + if ((colour & 0xFF) == 14 && _editorInventionsListDraggedItem == NULL) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = -2; + colour = 64 | w->colours[1]; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = 224; + colour = 0; + } + + left = 1; + top = itemY - 1; + gfx_draw_string(dpi, buffer, colour, left, top); + }while(researchItem++->entryIndex != researchItemEndMarker); +} + +#pragma region Drag item + +/** + * + * rct2: 0x006852F4 + */ +static void window_editor_inventions_list_drag_open(rct_research_item *researchItem) +{ + char buffer[256]; + int stringWidth; + rct_string_id stringId; + rct_window *w; + + window_close_by_class(WC_EDITOR_INVENTION_LIST_DRAG); + _editorInventionsListDraggedItem = researchItem; + + stringId = research_item_get_name(researchItem->entryIndex & 0xFFFFFF); + format_string(buffer, stringId, NULL); + stringWidth = gfx_get_string_width(buffer); + window_editor_inventions_list_drag_widgets[0].right = stringWidth; + + w = window_create( + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) - (stringWidth / 2), + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) - 7, + stringWidth, + 14, + (uint32*)window_editor_inventions_list_drag_events, + WC_EDITOR_INVENTION_LIST_DRAG, + WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_SNAPPING + ); + w->widgets = window_editor_inventions_list_drag_widgets; + w->colours[1] = 2; + input_window_position_begin( + w, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) + ); +} + +/** + * + * rct2: 0x0068549C + */ +static void window_editor_inventions_list_drag_cursor() +{ + rct_window *w, *inventionListWindow; + rct_research_item *researchItem; + short widgetIndex, x, y; + int cursorId; + + window_cursor_get_registers(w, widgetIndex, x, y); + + inventionListWindow = window_find_by_class(WC_EDITOR_INVENTION_LIST); + if (inventionListWindow != NULL) { + researchItem = get_research_item_at(x, y); + if (researchItem != WindowHighlightedItem(inventionListWindow)) { + WindowHighlightedItem(inventionListWindow) = researchItem; + window_invalidate(inventionListWindow); + } + } + + cursorId = CURSOR_HAND_CLOSED; + window_cursor_set_registers(cursorId); +} + +/** + * + * rct2: 0x00685412 + */ +static void window_editor_inventions_list_drag_moved() +{ + rct_window *w; + rct_research_item *researchItem; + short x, y, widgetIndex; + + window_cursor_get_registers(w, widgetIndex, x, y); + + researchItem = get_research_item_at(x, y); + if (researchItem != NULL) + move_research_item(researchItem); + + window_close(w); + _editorInventionsListDraggedItem = NULL; + window_invalidate_by_class(WC_EDITOR_INVENTION_LIST); +} + +/** + * + * rct2: 0x006853D9 + */ +static void window_editor_inventions_list_drag_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_string_id stringId; + int x, y; + + window_paint_get_registers(w, dpi); + + x = w->x; + y = w->y + 2; + stringId = research_item_get_name(_editorInventionsListDraggedItem->entryIndex & 0xFFFFFF); + gfx_draw_string_left(dpi, 1193, &stringId, 32, x, y); +} + +#pragma endregion diff --git a/src/windows/editor_main.c b/src/windows/editor_main.c index d1231efaea..a9635b4e47 100644 --- a/src/windows/editor_main.c +++ b/src/windows/editor_main.c @@ -87,7 +87,7 @@ void window_editor_main_open() RCT2_GLOBAL(0x009E32B3, uint8) = 0; RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) = 0; - window_editor_top_toolbar_open(); + window_top_toolbar_open(); window_editor_bottom_toolbar_open(); } diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index b7f21646c2..6697ec28cc 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -19,33 +19,131 @@ *****************************************************************************/ #include "../addresses.h" +#include "../audio/audio.h" #include "../game.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../management/research.h" #include "../object.h" +#include "../ride/track.h" +#include "../scenario.h" +#include "error.h" +#include "../interface/themes.h" +#include "dropdown.h" + + +enum { + FILTER_RCT2 = (1 << 0), + FILTER_WW = (1 << 1), + FILTER_TT = (1 << 2), + FILTER_CUSTOM = (1 << 3), + + FILTER_RIDE_TRANSPORT = (1 << 5), + FILTER_RIDE_GENTLE = (1 << 6), + FILTER_RIDE_COASTER = (1 << 7), + FILTER_RIDE_THRILL = (1 << 8), + FILTER_RIDE_WATER = (1 << 9), + FILTER_RIDE_STALL = (1 << 10), + + + FILTER_ALL = 0x7EF, +} FILTER_FLAGS; + +uint32 _filter_flags; +uint16 _filter_object_counts[11]; +uint8 _filter_ride_tab; + +char _filter_string[41]; + +#define _FILTER_ALL ((_filter_flags & FILTER_ALL) == FILTER_ALL) +#define _FILTER_RCT2 (_filter_flags & FILTER_RCT2) +#define _FILTER_WW (_filter_flags & FILTER_WW) +#define _FILTER_TT (_filter_flags & FILTER_TT) +#define _FILTER_CUSTOM (_filter_flags & FILTER_CUSTOM) + +enum { + WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS, + WINDOW_OBJECT_SELECTION_PAGE_SMALL_SCENERY, + WINDOW_OBJECT_SELECTION_PAGE_LARGE_SCENERY, + WINDOW_OBJECT_SELECTION_PAGE_WALLS_FENCES, + WINDOW_OBJECT_SELECTION_PAGE_PATH_SIGNS, + WINDOW_OBJECT_SELECTION_PAGE_FOOTPATHS, + WINDOW_OBJECT_SELECTION_PAGE_PATH_EXTRAS, + WINDOW_OBJECT_SELECTION_PAGE_SCENERY_GROUPS, + WINDOW_OBJECT_SELECTION_PAGE_PARK_ENTRANCE, + WINDOW_OBJECT_SELECTION_PAGE_WATER, + WINDOW_OBJECT_SELECTION_PAGE_SCENARIO_DESCRIPTION, + WINDOW_OBJECT_SELECTION_PAGE_COUNT +}; #pragma region Widgets enum WINDOW_STAFF_LIST_WIDGET_IDX { - WIDX_EDITOR_OBJECT_SELECTION_BACKGROUND, // 0, 1 - WIDX_EDITOR_OBJECT_SELECTION_TITLE, // 1, 2 - WIDX_EDITOR_OBJECT_SELECTION_CLOSE, // 2, 4 - WIDX_EDITOR_OBJECT_SELECTION_TAB_CONTENT_PANEL, // 3, 8 - WIDX_EDITOR_OBJECT_SELECTION_TAB_1, // 4, 10 - WIDX_EDITOR_OBJECT_SELECTION_TAB_2, // 5, 20 - WIDX_EDITOR_OBJECT_SELECTION_TAB_3, // 6, 40 - WIDX_EDITOR_OBJECT_SELECTION_TAB_4, // 7, 80 - WIDX_EDITOR_OBJECT_SELECTION_TAB_5, // 8, 100 - WIDX_EDITOR_OBJECT_SELECTION_TAB_6, // 9, 200 - WIDX_EDITOR_OBJECT_SELECTION_TAB_7, // 10, 400 - WIDX_EDITOR_OBJECT_SELECTION_TAB_8, // 11, 800 - WIDX_EDITOR_OBJECT_SELECTION_TAB_9, // 12, 1000 - WIDX_EDITOR_OBJECT_SELECTION_TAB_10, // 13, 2000 - WIDX_EDITOR_OBJECT_SELECTION_TAB_11, // 14, 4000 - WIDX_EDITOR_OBJECT_SELECTION_DROPDOWN1, // 15, 8000 - WIDX_EDITOR_OBJECT_SELECTION_LIST, // 16, 10000 - WIDX_EDITOR_OBJECT_SELECTION_FLATBTN, // 17, 20000 - WIDX_EDITOR_OBJECT_SELECTION_DROPDOWN2, // 18, 40000 + WIDX_BACKGROUND, // 0, 1 + WIDX_TITLE, // 1, 2 + WIDX_CLOSE, // 2, 4 + WIDX_TAB_CONTENT_PANEL, // 3, 8 + WIDX_TAB_1, // 4, 10 + WIDX_TAB_2, // 5, 20 + WIDX_TAB_3, // 6, 40 + WIDX_TAB_4, // 7, 80 + WIDX_TAB_5, // 8, 100 + WIDX_TAB_6, // 9, 200 + WIDX_TAB_7, // 10, 400 + WIDX_TAB_8, // 11, 800 + WIDX_TAB_9, // 12, 1000 + WIDX_TAB_10, // 13, 2000 + WIDX_TAB_11, // 14, 4000 + WIDX_DROPDOWN1, // 15, 8000 + WIDX_LIST, // 16, 10000 + WIDX_PREVIEW, // 17, 20000 + WIDX_DROPDOWN2, // 18, 40000 + WIDX_FILTER_DROPDOWN, // 19, 80000 + WIDX_FILTER_STRING_BUTTON, // 20, 100000 + WIDX_FILTER_CLEAR_BUTTON, // 21, 200000 + WIDX_FILTER_RIDE_TAB_FRAME, + WIDX_FILTER_RIDE_TAB_ALL, + WIDX_FILTER_RIDE_TAB_TRANSPORT, + WIDX_FILTER_RIDE_TAB_GENTLE, + WIDX_FILTER_RIDE_TAB_COASTER, + WIDX_FILTER_RIDE_TAB_THRILL, + WIDX_FILTER_RIDE_TAB_WATER, + WIDX_FILTER_RIDE_TAB_STALL +}; + +static rct_widget window_editor_object_selection_widgets[] = { + { WWT_FRAME, 0, 0, 599, 0, 399, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 598, 1, 14, 3181, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 587, 597, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 599, 43, 399, 0xFFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, 1812 }, + { WWT_TAB, 1, 313, 343, 17, 43, 0x2000144E, 1812 }, + { WWT_DROPDOWN_BUTTON, 0, 470, 591, 23, 34, STR_OBJECT_SELECTION_ADVANCED, STR_OBJECT_SELECTION_ADVANCED_TIP }, + { WWT_SCROLL, 1, 4, 291, 60, 386, 2, STR_NONE }, + { WWT_FLATBTN, 1, 391, 504, 46, 159, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 0, 384, 595, 24, 35, STR_INSTALL_NEW_TRACK_DESIGN, STR_INSTALL_NEW_TRACK_DESIGN_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 350, 463, 23, 34, 5261, 5265 }, + { WWT_TEXT_BOX, 1, 4, 214, 46, 57, (uint32)_filter_string, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 218, 287, 46, 57, 5277, STR_NONE }, + { WWT_RESIZE, 1, 3, 287, 73, 76, 0xFFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 47, 73, 0x2000144E, 5349 }, + { WWT_TAB, 1, 34, 64, 47, 73, 0x2000144E, 1223 }, + { WWT_TAB, 1, 65, 95, 47, 73, 0x2000144E, 1224 }, + { WWT_TAB, 1, 96, 126, 47, 73, 0x2000144E, 1225 }, + { WWT_TAB, 1, 127, 157, 47, 73, 0x2000144E, 1226 }, + { WWT_TAB, 1, 158, 188, 47, 73, 0x2000144E, 1227 }, + { WWT_TAB, 1, 189, 219, 47, 73, 0x2000144E, 1228 }, + { WIDGETS_END } }; #pragma endregion @@ -54,12 +152,28 @@ enum WINDOW_STAFF_LIST_WIDGET_IDX { static void window_editor_object_selection_emptysub() { } +static void window_editor_object_selection_close(); static void window_editor_object_selection_mouseup(); +static void window_editor_object_selection_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_editor_object_selection_dropdown(); +static void window_editor_object_selection_update(rct_window *w); +static void window_editor_object_selection_scrollgetsize(); +static void window_editor_object_selection_scroll_mousedown(); +static void window_editor_object_selection_scroll_mouseover(); +static void window_editor_object_selection_tooltip(); +static void window_editor_object_selection_invalidate(); +static void window_editor_object_selection_paint(); +static void window_editor_object_selection_scrollpaint(); +static void window_editor_object_selection_textinput(); static void* window_editor_object_selection_events[] = { - (void*)0x006AB199, + window_editor_object_selection_close, (void*)window_editor_object_selection_mouseup, (void*)window_editor_object_selection_emptysub, + (void*)window_editor_object_selection_mousedown, + (void*)window_editor_object_selection_dropdown, + (void*)window_editor_object_selection_emptysub, + (void*)window_editor_object_selection_update, (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, @@ -68,28 +182,75 @@ static void* window_editor_object_selection_events[] = { (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, + (void*)window_editor_object_selection_scrollgetsize, + (void*)window_editor_object_selection_scroll_mousedown, + (void*)window_editor_object_selection_emptysub, + (void*)window_editor_object_selection_scroll_mouseover, + (void*)window_editor_object_selection_textinput, (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, + (void*)window_editor_object_selection_tooltip, (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, - (void*)0x006AB031, - (void*)0x006AB0B6, - (void*)window_editor_object_selection_emptysub, - (void*)0x006AB079, - (void*)window_editor_object_selection_emptysub, - (void*)window_editor_object_selection_emptysub, - (void*)window_editor_object_selection_emptysub, - (void*)0x006AB058, - (void*)window_editor_object_selection_emptysub, - (void*)window_editor_object_selection_emptysub, - (void*)0x006AA9FD, - (void*)0x006AAB56, - (void*)0x006AADA3 + (void*)window_editor_object_selection_invalidate, + (void*)window_editor_object_selection_paint, + (void*)window_editor_object_selection_scrollpaint }; #pragma endregion static void window_editor_object_set_page(rct_window *w, int page); +static void window_editor_object_selection_set_pressed_tab(rct_window *w); +static void window_editor_object_selection_select_default_objects(); +static int window_editor_object_selection_select_object(int flags, rct_object_entry *entry); +static int get_object_from_object_selection(uint8 object_type, int y, uint8 *object_selection_flags, rct_object_entry **installed_entry); +static void window_editor_object_selection_manage_tracks(); +static void editor_load_selected_objects(); +static bool filter_string(rct_object_entry *entry); +static bool filter_source(rct_object_entry *entry); +static bool filter_chunks(rct_object_entry *entry, rct_object_filters *filter); +static void filter_update_counts(); + +static rct_object_entry DefaultSelectedObjects[] = { + // Objects that are always required + { 0x00000087, { "SCGTREES" }, 0 }, // Scenery: Trees + { 0x00000087, { "SCGSHRUB" }, 0 }, // Scenery: Shrubs and Ornaments + { 0x00000087, { "SCGGARDN" }, 0 }, // Scenery: Gardens + { 0x00000087, { "SCGFENCE" }, 0 }, // Scenery: Fences and Walls + { 0x00000087, { "SCGWALLS" }, 0 }, // Scenery: Walls and Roofs + { 0x00000087, { "SCGPATHX" }, 0 }, // Scenery: Signs and Items for Footpaths + { 0x00000085, { "TARMAC " }, 0 }, // Footpath: Tarmac + + // An initial default selection + { 0x000080FF, { "TWIST1 " }, 0 }, // Ride: Twist + { 0x00008000, { "PTCT1 " }, 0 }, // Ride: Wooden Roller Coaster (Wooden Roller Coaster Trains) + { 0x00008000, { "ZLDB " }, 0 }, // Ride: Junior Roller Coaster (Ladybird Trains) + { 0x00008000, { "LFB1 " }, 0 }, // Ride: Log Flume + { 0x00008000, { "VCR " }, 0 }, // Ride: Vintage Cars + { 0x00008000, { "MGR1 " }, 0 }, // Ride: Merry-Go-Round + { 0x00008000, { "TLT1 " }, 0 }, // Ride: Restroom + { 0x00008000, { "ATM1 " }, 0 }, // Ride: Cash Machine + { 0x00008000, { "FAID1 " }, 0 }, // Ride: First Aid Room + { 0x00008000, { "INFOK " }, 0 }, // Ride: Information Kiosk + { 0x00008000, { "DRNKS " }, 0 }, // Ride: Drinks Stall + { 0x00008000, { "CNDYF " }, 0 }, // Ride: Cotten Candy Stall + { 0x00008000, { "BURGB " }, 0 }, // Ride: Burger Bar + { 0x00008000, { "BALLN " }, 0 }, // Ride: Balloon Stall + { 0x00008000, { "ARRT1 " }, 0 }, // Ride: Corkscrew Roller Coaster + { 0x00008000, { "RBOAT " }, 0 }, // Ride: Rowing Boats + { 0x00008800, { "PKENT1 " }, 0 }, // Park Entrace: Traditional Park Entrance + { 0x00008900, { "WTRCYAN " }, 0 }, // Water: Natural Water + { 0x00008500, { "TARMACB " }, 0 }, // Footpath: Brown Tarmac Footpath + { 0x00008500, { "PATHSPC " }, 0 }, // Footpath: Space Style Footpath + { 0x00008500, { "PATHDIR " }, 0 }, // Footpath: Dirt Footpath + { 0x00008500, { "PATHCRZ " }, 0 }, // Footpath: Crazy Paving Footpath + { 0x00008500, { "PATHASH " }, 0 }, // Footpath: Ash Footpath + + // The following are for all random map generation features to work out the box + { 0x00000087, { "SCGJUNGL" }, 0 }, // Jungle Themeing + { 0x00000087, { "SCGSNOW " }, 0 }, // Snow and Ice Themeing + { 0x00000087, { "SCGWATER" }, 0 } // Water Feature Themeing +}; /** * @@ -106,23 +267,31 @@ void window_editor_object_selection_open() RCT2_CALLPROC_EBPSAFE(0x006AB211); RCT2_CALLPROC_EBPSAFE(0x006AA770); - window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 300, - max(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 200, 28), + // Not really where its called, but easy way to change default objects for now + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) + window_editor_object_selection_select_default_objects(); + + window = window_create_centred( 600, 400, (uint32*)window_editor_object_selection_events, WC_EDITOR_OBJECT_SELECTION, - WF_STICK_TO_FRONT + WF_10 ); - window->widgets = (rct_widget*)0x009ADB00; + window->widgets = window_editor_object_selection_widgets; window->enabled_widgets = - (1 << WIDX_EDITOR_OBJECT_SELECTION_DROPDOWN1) | - (1 << WIDX_EDITOR_OBJECT_SELECTION_DROPDOWN2) | - (1 << WIDX_EDITOR_OBJECT_SELECTION_CLOSE); + (1 << WIDX_DROPDOWN1) | + (1 << WIDX_DROPDOWN2) | + (1 << WIDX_FILTER_DROPDOWN) | + (1 << WIDX_FILTER_STRING_BUTTON) | + (1 << WIDX_FILTER_CLEAR_BUTTON) | + (1 << WIDX_CLOSE); - for (int i = WIDX_EDITOR_OBJECT_SELECTION_TAB_1; i <= WIDX_EDITOR_OBJECT_SELECTION_TAB_11; i++) + _filter_flags = FILTER_ALL; + memset(_filter_string, 0, sizeof(_filter_string)); + + for (int i = WIDX_TAB_1; i <= WIDX_TAB_11; i++) window->enabled_widgets |= (1LL << i); window_init_scroll_widgets(window); @@ -130,11 +299,44 @@ void window_editor_object_selection_open() window->selected_tab = 0; window->selected_list_item = -1; window->var_494 = 0xFFFFFFFF; - window->colours[0] = 4; - window->colours[1] = 1; - window->colours[2] = 1; } +/** + * + * rct2: 0x006AB199 + */ +static void window_editor_object_selection_close() +{ + rct_window* w; + window_get_register(w); + + //if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR)) + // return; + + RCT2_CALLPROC_EBPSAFE(0x6ABB66); + editor_load_selected_objects(); + reset_loaded_objects(); + object_free_scenario_text(); + RCT2_CALLPROC_EBPSAFE(0x6AB316); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR) { + research_populate_list_random(); + research_remove_non_separate_vehicle_types(); + } + else { + // Used for in-game object selection cheat + research_reset_items(); + research_populate_list_researched(); + gSilentResearch = true; + sub_684AC3(); + gSilentResearch = false; + } + window_new_ride_init_vars(); +} + +/** + * + * rct2: 0x006AAFAB + */ static void window_editor_object_selection_mouseup() { rct_window *w; @@ -143,43 +345,668 @@ static void window_editor_object_selection_mouseup() window_widget_get_registers(w, widgetIndex); switch (widgetIndex) { - case WIDX_EDITOR_OBJECT_SELECTION_CLOSE: - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); + case WIDX_CLOSE: + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR) { + game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); + } + else { + // Used for in-game object selection cheat + window_close(w); + } break; - case WIDX_EDITOR_OBJECT_SELECTION_TAB_1: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_2: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_3: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_4: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_5: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_6: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_7: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_8: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_9: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_10: - case WIDX_EDITOR_OBJECT_SELECTION_TAB_11: - window_editor_object_set_page(w, widgetIndex - WIDX_EDITOR_OBJECT_SELECTION_TAB_1); + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + case WIDX_TAB_11: + window_editor_object_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_FILTER_RIDE_TAB_ALL: + _filter_flags |= 0x7E0; + filter_update_counts(); + + w->selected_list_item = -1; + w->var_494 = 0xFFFFFFFF; + w->scrolls[0].v_top = 0; + object_free_scenario_text(); + window_invalidate(w); + break; + case WIDX_FILTER_RIDE_TAB_TRANSPORT: + case WIDX_FILTER_RIDE_TAB_GENTLE: + case WIDX_FILTER_RIDE_TAB_COASTER: + case WIDX_FILTER_RIDE_TAB_THRILL: + case WIDX_FILTER_RIDE_TAB_WATER: + case WIDX_FILTER_RIDE_TAB_STALL: + _filter_flags &= ~0x7E0; + _filter_flags |= (1 << (widgetIndex - WIDX_FILTER_RIDE_TAB_TRANSPORT + 5)); + + filter_update_counts(); + + w->selected_list_item = -1; + w->var_494 = 0xFFFFFFFF; + w->scrolls[0].v_top = 0; + object_free_scenario_text(); + window_invalidate(w); break; - case WIDX_EDITOR_OBJECT_SELECTION_DROPDOWN1: + case WIDX_DROPDOWN1: w->list_information_type ^= 1; window_invalidate(w); break; - case WIDX_EDITOR_OBJECT_SELECTION_DROPDOWN2: + case WIDX_DROPDOWN2: if (w->selected_list_item != -1) { w->selected_list_item = -1; - RCT2_CALLPROC_EBPSAFE(0x006A982D); // object_free_scenario_text(); + object_free_scenario_text(); } window_invalidate(w); - int eax, ebx, ecx, edx, esi, edi, ebp; - RCT2_CALLFUNC_X(0x00674FCE, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (eax == 1) { - window_close(w); - RCT2_CALLPROC_EBPSAFE(0x006D386D); - } + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK, NULL); break; + case WIDX_FILTER_STRING_BUTTON: + //window_text_input_open(w, widgetIndex, 5275, 5276, 1170, (uint32)_filter_string, 40); + window_start_textbox(w, widgetIndex, 1170, (uint32)_filter_string, 40); + break; + case WIDX_FILTER_CLEAR_BUTTON: + memset(_filter_string, 0, sizeof(_filter_string)); + + w->scrolls->v_top = 0; + + window_invalidate(w); + break; + } +} + +void window_editor_object_selection_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) +{ + int num_items; + + //widget = &w->widgets[widgetIndex - 1]; + + switch (widgetIndex) { + case WIDX_FILTER_DROPDOWN: + + num_items = 4; + gDropdownItemsFormat[0] = 1156; + gDropdownItemsFormat[1] = 1156; + gDropdownItemsFormat[2] = 1156; + gDropdownItemsFormat[3] = 1156; + gDropdownItemsArgs[0] = 2741; + gDropdownItemsArgs[1] = 5262; + gDropdownItemsArgs[2] = 5263; + gDropdownItemsArgs[3] = 5264; + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[widget->colour], + DROPDOWN_FLAG_STAY_OPEN, + num_items + ); + + gDropdownItemsChecked = _filter_flags & 0xF; + break; + + } +} + +static void window_editor_object_selection_dropdown() +{ + short dropdownIndex; + short widgetIndex; + rct_window *w; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (dropdownIndex == -1) + return; + switch (widgetIndex) { + case WIDX_FILTER_DROPDOWN: + _filter_flags ^= (1 << dropdownIndex); + + filter_update_counts(); + w->scrolls->v_top = 0; + + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x006AB031 + */ +static void window_editor_object_selection_scrollgetsize() +{ + rct_window *w; + short scrollIndex; + int numItems, width, height; + + window_scroll_get_registers(w, scrollIndex); + + numItems = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER) ? + RCT2_GLOBAL(0x00F43412, uint16) : + ((_FILTER_ALL && _filter_string[0] == 0) ? + RCT2_ADDRESS(0x00F433E1, uint16)[w->selected_tab] : + _filter_object_counts[w->selected_tab]); + + width = 0; + height = numItems * 12; + window_scrollsize_set_registers(width, height); +} + +/** + * + * rct2: 0x006AB0B6 + */ +static void window_editor_object_selection_scroll_mousedown() +{ + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + // Used for in-game object selection cheat to prevent crashing the game + // when windows attempt to draw objects that don't exist any more + window_close_all_except_class(WC_EDITOR_OBJECT_SELECTION); + + uint8 object_selection_flags; + rct_object_entry* installed_entry; + int selected_object = get_object_from_object_selection((w->selected_tab & 0xFF), y, &object_selection_flags, &installed_entry); + if (selected_object == -1 || (object_selection_flags & 0x20)) + return; + + window_invalidate(w); + + sound_play_panned(SOUND_CLICK_1, RCT2_GLOBAL(0x142406C,uint32), 0, 0, 0); + + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + if (!window_editor_object_selection_select_object(1, installed_entry)) + return; + + // Close any other open windows such as options/colour schemes to prevent a crash. + window_close_all(); + //window_close(w); + + //This function calls window_track_list_open + window_editor_object_selection_manage_tracks(); + return; + } + + int ebx = 6; + // If already selected + if (!(object_selection_flags & 1)) + ebx = 7; + + RCT2_GLOBAL(0xF43411, uint8) = 0; + if (!window_editor_object_selection_select_object(ebx, installed_entry)) { + rct_string_id error_title = ebx & 1 ? + STR_UNABLE_TO_SELECT_THIS_OBJECT : + STR_UNABLE_TO_DE_SELECT_THIS_OBJECT; + + window_error_open(error_title, RCT2_GLOBAL(0x141E9AC, uint16)); + return; + } + + if (!RCT2_GLOBAL(0xF43411, uint8) & 1) + return; + + window_error_open(STR_WARNING_TOO_MANY_OBJECTS_SELECTED, STR_NOT_ALL_OBJECTS_IN_THIS_SCENERY_GROUP_COULD_BE_SELECTED); +} + +/** + * + * rct2: 0x006AB079 + */ +static void window_editor_object_selection_scroll_mouseover() +{ + rct_window *w; + rct_object_entry *installedEntry; + int selectedObject; + short x, y, scrollIndex; + uint8 objectSelectionFlags; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + selectedObject = get_object_from_object_selection( + w->selected_tab & 0xFF, y, &objectSelectionFlags, &installedEntry + ); + if (objectSelectionFlags & 0x20) + selectedObject = -1; + + if (selectedObject == w->selected_list_item) + return; + + w->selected_list_item = selectedObject; + w->var_494 = (uint32)installedEntry; + object_free_scenario_text(); + if (selectedObject != -1) + object_get_scenario_text(installedEntry); + + window_invalidate(w); +} + +/** + * + * rct2: 0x006AB058 + */ +static void window_editor_object_selection_tooltip() +{ + rct_window *w; + short widgetIndex; + + window_scroll_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + case WIDX_TAB_11: + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, rct_string_id) = + STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS + (widgetIndex - WIDX_TAB_1); + break; + default: + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, rct_string_id) = STR_LIST; + break; + } +} + +/** + * + * rct2: 0x006AA9FD + */ +static void window_editor_object_selection_invalidate() +{ + int i, x; + rct_window *w; + rct_widget *widget; + + window_get_register(w); + colour_scheme_update(w); + + // Set pressed widgets + w->pressed_widgets |= 1 << WIDX_PREVIEW; + window_editor_object_selection_set_pressed_tab(w); + if (w->list_information_type & 1) + w->pressed_widgets |= (1 << WIDX_DROPDOWN1); + else + w->pressed_widgets &= ~(1 << WIDX_DROPDOWN1); + + // Set window title and buttons + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, rct_string_id) = STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS + w->selected_tab; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + w->widgets[WIDX_TITLE].image = STR_TRACK_DESIGNS_MANAGER_SELECT_RIDE_TYPE; + w->widgets[WIDX_CLOSE].type = WWT_EMPTY; + w->widgets[WIDX_DROPDOWN2].type = WWT_DROPDOWN_BUTTON; + } else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) { + w->widgets[WIDX_TITLE].image = STR_ROLLER_COASTER_DESIGNER_SELECT_RIDE_TYPES_VEHICLES; + w->widgets[WIDX_CLOSE].type = WWT_CLOSEBOX; + w->widgets[WIDX_DROPDOWN2].type = WWT_EMPTY; + } else { + w->widgets[WIDX_TITLE].image = STR_OBJECT_SELECTION; + w->widgets[WIDX_CLOSE].type = WWT_CLOSEBOX; + w->widgets[WIDX_DROPDOWN2].type = WWT_EMPTY; + } + + // Align tabs, hide advanced ones + x = 3; + for (i = 0; i < WINDOW_OBJECT_SELECTION_PAGE_COUNT; i++) { + widget = &w->widgets[WIDX_TAB_1 + i]; + + if (!(w->list_information_type & 1) && ((1 << i) & 0x5E)) { + widget->type = WWT_EMPTY; + } else { + widget->type = WWT_TAB; + widget->left = x; + widget->right = x + 30; + x += 31; + } + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TRACK_DESIGNER)) { + w->widgets[WIDX_DROPDOWN1].type = WWT_EMPTY; + w->widgets[WIDX_FILTER_DROPDOWN].type = WWT_EMPTY; + for (i = 1; i < WINDOW_OBJECT_SELECTION_PAGE_COUNT; i++) + w->widgets[WIDX_TAB_1 + i].type = WWT_EMPTY; + x = 150; + } else { + w->widgets[WIDX_DROPDOWN1].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_FILTER_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + x = 300; + } + + w->widgets[WIDX_LIST].right = 587 - x; + w->widgets[WIDX_PREVIEW].left = 537 - (x >> 1); + w->widgets[WIDX_PREVIEW].right = w->widgets[WIDX_PREVIEW].left + 113; + + bool ridePage = (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS); + w->widgets[WIDX_LIST].top = (ridePage ? 94 : 60); + w->widgets[WIDX_FILTER_STRING_BUTTON].top = (ridePage ? 80 : 46); + w->widgets[WIDX_FILTER_STRING_BUTTON].bottom = (ridePage ? 91 : 57); + w->widgets[WIDX_FILTER_CLEAR_BUTTON].top = (ridePage ? 80 : 46); + w->widgets[WIDX_FILTER_CLEAR_BUTTON].bottom = (ridePage ? 91 : 57); + + if (ridePage) { + w->enabled_widgets |= (1 << WIDX_FILTER_RIDE_TAB_ALL) | (1 << WIDX_FILTER_RIDE_TAB_TRANSPORT) | + (1 << WIDX_FILTER_RIDE_TAB_GENTLE) | (1 << WIDX_FILTER_RIDE_TAB_COASTER) | (1 << WIDX_FILTER_RIDE_TAB_THRILL) | + (1 << WIDX_FILTER_RIDE_TAB_WATER) | (1 << WIDX_FILTER_RIDE_TAB_STALL); + for (i = 0; i < 7; i++) + w->pressed_widgets &= ~(1 << (WIDX_FILTER_RIDE_TAB_ALL + i)); + if ((_filter_flags & 0x7E0) == 0x7E0) + w->pressed_widgets |= (1 << WIDX_FILTER_RIDE_TAB_ALL); + else { + for (int i = 0; i < 6; i++) { + if (_filter_flags & (1 << (5 + i))) + w->pressed_widgets |= (uint64)(1 << (WIDX_FILTER_RIDE_TAB_TRANSPORT + i)); + } + } + w->widgets[WIDX_FILTER_RIDE_TAB_FRAME].type = WWT_RESIZE; + for (int i = WIDX_FILTER_RIDE_TAB_ALL; i <= WIDX_FILTER_RIDE_TAB_STALL; i++) + w->widgets[i].type = WWT_TAB; + } + else { + w->enabled_widgets &= ~((1 << WIDX_FILTER_RIDE_TAB_ALL) | (1 << WIDX_FILTER_RIDE_TAB_TRANSPORT) | + (1 << WIDX_FILTER_RIDE_TAB_GENTLE) | (1 << WIDX_FILTER_RIDE_TAB_COASTER) | (1 << WIDX_FILTER_RIDE_TAB_THRILL) | + (1 << WIDX_FILTER_RIDE_TAB_WATER) | (1 << WIDX_FILTER_RIDE_TAB_STALL)); + for (int i = WIDX_FILTER_RIDE_TAB_FRAME; i <= WIDX_FILTER_RIDE_TAB_STALL; i++) + w->widgets[i].type = WWT_EMPTY; + } +} + +/** + * + * rct2: 0x006AAB56 + */ +static void window_editor_object_selection_paint() +{ + int i, x, y, width, numSelected, totalSelectable, type; + rct_window *w; + rct_drawpixelinfo *dpi; + rct_widget *widget; + rct_object_entry *highlightedEntry; + rct_string_id stringId; + uint8 *text, source; + char *datName, *name, *stringBuffer; + + window_paint_get_registers(w, dpi); + + /*if (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { + gfx_fill_rect_inset(dpi, + w->x + w->widgets[WIDX_FILTER_RIDE_TAB_ALL].left - 1, + w->y + w->widgets[WIDX_FILTER_RIDE_TAB_ALL].bottom, + w->x + w->widgets[WIDX_FILTER_RIDE_TAB_STALL].right + 1, + w->y + w->widgets[WIDX_FILTER_RIDE_TAB_ALL].bottom + 2, + w->colours[1], + 0x10 + ); + }*/ + + window_draw_widgets(w, dpi); + + // Draw tabs + for (i = 0; i < WINDOW_OBJECT_SELECTION_PAGE_COUNT; i++) { + widget = &w->widgets[WIDX_TAB_1 + i]; + if (widget->type == WWT_EMPTY) + continue; + + x = w->x + widget->left; + y = w->y + widget->top; + gfx_draw_sprite(dpi, 5458 + i, x, y, 0); + } + + const int ride_tabs[] = { 5458, 0x200015A1, 5542, 0x200015AA, 5557 + 5, 5551, 5530, 5327 }; + + // Draw ride tabs + if (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { + for (i = 0; i < 7; i++) { + widget = &w->widgets[WIDX_FILTER_RIDE_TAB_ALL + i]; + if (widget->type == WWT_EMPTY) + continue; + + x = w->x + widget->left; + y = w->y + widget->top; + gfx_draw_sprite(dpi, ride_tabs[i] | (w->colours[1] << 19), x, y, 0); + } + + } + + // Preview background + widget = &w->widgets[WIDX_PREVIEW]; + gfx_fill_rect( + dpi, + w->x + widget->left + 1, + w->y + widget->top + 1, + w->x + widget->right - 1, + w->y + widget->bottom - 1, + RCT2_ADDRESS(0x0141FC44, uint8)[w->colours[1] * 8] + ); + + // Draw number of selected items + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { + x = w->x + 3; + y = w->y + w->height - 13; + + numSelected = RCT2_ADDRESS(0x00F433F7, uint16)[w->selected_tab]; + totalSelectable = object_entry_group_counts[w->selected_tab]; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) + totalSelectable = 4; + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = numSelected; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint16) = totalSelectable; + gfx_draw_string_left(dpi, 3164, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, 0, x, y); + } + + rct_stex_entry* stex_entry = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, rct_stex_entry*); + + /*gfx_fill_rect_inset(dpi, + w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].left, + w->y + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].top, + w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].right, + w->y + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].bottom, + w->colours[1], + 0x30 + ); + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&_filter_string; + gfx_draw_string_left_clipped( + dpi, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, + w->colours[1], + w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].left + 1, + w->y + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].top, + w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].right + );*/ + + if (w->selected_list_item == -1 || stex_entry == NULL) + return; + + highlightedEntry = (rct_object_entry*)w->var_494; + type = highlightedEntry->flags & 0x0F; + + // Draw preview + widget = &w->widgets[WIDX_PREVIEW]; + x = w->x + (widget->left + widget->right) / 2 + 1; + y = w->y + (widget->top + widget->bottom) / 2 + 1; + object_paint(type, 3, type, x, y, 0, (int)dpi, (int)stex_entry); + + // Draw name of object + x = w->x + (widget->left + widget->right) / 2 + 1; + y = w->y + widget->bottom + 3; + width = w->width - w->widgets[WIDX_LIST].right - 6; + + // Skip object dat name + text = (char*)(highlightedEntry + 1); + datName = text; + do { + text++; + } while (*(text - 1) != 0); + text += 4; + name = text; + + RCT2_GLOBAL(0x009BC677, uint8) = 14; + + stringId = 3165; + stringBuffer = (char*)language_get_string(3165) + 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { + // Skip name + do { + text++; + } while (*(text - 1) != 0); + text += 4; + text += *text * 16 + 1; + text += *text * 16 + 1; + + if (RCT2_GLOBAL(text, uint32) & 0x1000000) { + strcpy(stringBuffer, name); + } else { + int eax = *text; + if (*text == 0xFF) { + eax = *(text + 1); + if (*(text + 1) == 0xFF) + eax = *(text + 2); + } + format_string(stringBuffer, eax + 2, NULL); + } + } else { + strcpy(stringBuffer, name); + } + gfx_draw_string_centred_clipped(dpi, stringId, NULL, 0, x, y, width); + + // Draw description of object + x = w->x + w->widgets[WIDX_LIST].right + 4; + y += 15; + object_paint(type, 259, type, x, y, (int)w, (int)dpi, (int)stex_entry); + + // Draw object source + source = (highlightedEntry->flags & 0xF0) >> 4; + switch (source) { + case 8: stringId = 2741; break; + case 1: stringId = 5262; break; + case 2: stringId = 5263; break; + default: stringId = 5264; break; + } + gfx_draw_string_right(dpi, stringId, NULL, 2, w->x + w->width - 5, w->y + w->height - 3 - 12 - 14); + + // + if (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { + y = w->y + w->height - 3 - 12 - 14 - 14; + + rct_ride_type *rideType = (rct_ride_type*)stex_entry; + for (int i = 0; i < 3; i++) { + if (rideType->ride_type[i] == 255) + continue; + + stringId = 2 + rideType->ride_type[i]; + gfx_draw_string_right(dpi, stringId, NULL, 2, w->x + w->width - 5, y); + y -= 11; + } + } + + //stringId = highlightedEntry->checksum + // gfx_draw_string_right(dpi, stringId, NULL, 2, w->x + w->width - 5, w->y + w->height - 3 - 12 - 14); + + // Draw object dat name + stringId = 3165; + strcpy(stringBuffer, datName); + gfx_draw_string_right(dpi, stringId, NULL, 0, w->x + w->width - 5, w->y + w->height - 3 - 12); +} + +/** + * + * rct2: 0x006AADA3 + */ +static void window_editor_object_selection_scrollpaint() +{ + int x, y, i, colour, colour2, numObjects, type; + short scrollIndex; + rct_object_entry *entry; + rct_object_filters *filter; + rct_window *w; + rct_drawpixelinfo *dpi; + uint8 *itemFlags; + uint8 source; + + window_scrollpaint_get_registers(w, dpi, scrollIndex); + + colour = RCT2_ADDRESS(0x0141FC48, uint8)[w->colours[1] * 8]; + colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; + gfx_clear(dpi, colour); + + numObjects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, sint32); + entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + itemFlags = RCT2_GLOBAL(0x009ADAEC, uint8*); + y = 0; + for (i = 0; i < numObjects; i++) { + filter = get_object_filter(i); + type = entry->flags & 0x0F; + source = (entry->flags & 0xF0) >> 4; + if (type == w->selected_tab && !(*itemFlags & 0x20) && filter_source(entry) && filter_string(entry) && filter_chunks(entry, filter)) { + if (y + 12 >= dpi->y && y <= dpi->y + dpi->height) { + // Draw checkbox + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && !(*itemFlags & 0x20)) + gfx_fill_rect_inset(dpi, 2, y, 11, y + 10, w->colours[1], 0xE0); + + // Highlight background + colour = 142; + if (entry == (rct_object_entry*)w->var_494 && !(*itemFlags & 0x20)) { + gfx_fill_rect(dpi, 0, y, w->width, y + 11, 0x2000031); + colour = 14; + } + + // Draw checkmark + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && (*itemFlags & 1)) { + x = 2; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = colour == 14 ? -2 : -1; + colour2 = w->colours[1] & 0x7F; + if (*itemFlags & 0x1C) + colour2 |= 0x40; + + gfx_draw_string(dpi, (char*)0x009DED72, colour2, x, y); + } + + // Draw text + char *buffer = (char*)0x0141ED68; + *buffer = colour; + strcpy(buffer + 1, object_get_name(entry)); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + while (*buffer != 0 && *buffer != 9) + buffer++; + + *buffer = 0; + } + + if (*itemFlags & 0x20) { + colour = w->colours[1] & 0x7F; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = -1; + } else { + colour = 0; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = 224; + } + x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 15; + gfx_draw_string(dpi, (char*)0x0141ED68, colour, x, y); + } + y += 12; + } + + entry = object_get_next(entry); + itemFlags++; } } @@ -192,6 +1019,241 @@ static void window_editor_object_set_page(rct_window *w, int page) w->selected_list_item = -1; w->var_494 = 0xFFFFFFFF; w->scrolls[0].v_top = 0; - RCT2_CALLPROC_EBPSAFE(0x006A982D); // object_free_scenario_text(); + object_free_scenario_text(); window_invalidate(w); -} \ No newline at end of file +} + +static void window_editor_object_selection_set_pressed_tab(rct_window *w) +{ + int i; + for (i = 0; i < WINDOW_OBJECT_SELECTION_PAGE_COUNT; i++) + w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->selected_tab); +} + +/** + * + * rct2: 0x006AA7E9 + */ +static void window_editor_object_selection_select_default_objects() +{ + int i; + + if (RCT2_GLOBAL(0x00F433F7, uint16) == 0) + return; + + for (i = 0; i < countof(DefaultSelectedObjects); i++) + window_editor_object_selection_select_object(7, &DefaultSelectedObjects[i]); +} + +/** + * + * rct2: 0x006AB54F + */ +static int window_editor_object_selection_select_object(int flags, rct_object_entry *entry) +{ + return (RCT2_CALLPROC_X(0x006AB54F, 0, flags, 0, 0, 0, 0, (int)entry) & 0x100) == 0; +} + +/** + * Takes the y coordinate of the clicked on scroll list + * and converts this into an object selection. + * Returns the position in the list. + * Object_selection_flags, installed_entry also populated + * + * rct2: 0x006AA703 + */ +static int get_object_from_object_selection(uint8 object_type, int y, uint8 *object_selection_flags, rct_object_entry **installed_entry) +{ + rct_object_filters *filter; + *installed_entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + uint8 source; + int object_count = 0; + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + filter = get_object_filter(RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) - i); + source = ((*installed_entry)->flags & 0xF0) >> 4; + if (((*installed_entry)->flags & 0xF) == object_type && filter_source(*installed_entry) && filter_string(*installed_entry) && filter_chunks(*installed_entry, filter)){ + if (!(*selection_flags & 0x20)){ + y -= 12; + *object_selection_flags = *selection_flags; + if (y < 0)return object_count; + object_count++; + } + } + + *installed_entry = object_get_next(*installed_entry); + selection_flags++; + } + return -1; +} + +/** + * + * rct2: 0x006D33E2 + */ +static void window_editor_object_selection_manage_tracks() +{ + RCT2_GLOBAL(0x1357404, sint32) = -1; + RCT2_GLOBAL(0x1357408, sint32) = -1; + RCT2_GLOBAL(0x135740C, sint32) = -1; + RCT2_GLOBAL(0x1357410, sint32) = -1; + + for (int i = 0; i < 128; ++i){ + RCT2_ADDRESS(0x1357444, uint32)[i] = RCT2_ADDRESS(0x97C468, uint32)[i]; + RCT2_ADDRESS(0x1357644, uint32)[i] = RCT2_ADDRESS(0x97C5D4, uint32)[i]; + } + + for (int i = 0; i < 8; ++i){ + RCT2_ADDRESS(0x1357424, sint32)[i] = -1; + } + + RCT2_GLOBAL(0x141F570, uint8) = 7; + + int entry_index = 0; + for (; ((int)object_entry_groups[0].chunks[entry_index]) == -1; ++entry_index); + + RCT2_GLOBAL(0xF44157, uint8) = entry_index; + + rct_ride_type* ride_entry = GET_RIDE_ENTRY(entry_index); + uint8* ride_type_array = &ride_entry->ride_type[0]; + + int ride_type; + for (int i = 0; (ride_type = ride_type_array[i]) == 0xFF; i++); + RCT2_GLOBAL(0xF44158, uint8) = ride_type; + + ride_list_item item = { ride_type, entry_index }; + track_load_list(item); + window_track_list_open(item); +} + +/** + * + * rct2: 0x006ABBBE + */ +static void editor_load_selected_objects() +{ + uint8 *selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry *installed_entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) == 0) + return; + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i != 0; i--, selection_flags++) { + if (*selection_flags & 1) { + uint8 entry_index, entry_type; + if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){ + int chunk_size; + if (!object_load(-1, installed_entry, &chunk_size)) { + log_error("Failed to load entry %.8s", installed_entry->name); + } + } + } + + installed_entry = object_get_next(installed_entry); + } +} + +static void window_editor_object_selection_update(rct_window *w) +{ + if (gCurrentTextBox.window.classification == w->classification && + gCurrentTextBox.window.number == w->number) { + window_update_textbox_caret(); + widget_invalidate(w, WIDX_FILTER_STRING_BUTTON); + } +} + +static void window_editor_object_selection_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (widgetIndex != WIDX_FILTER_STRING_BUTTON || !result) + return; + + if (strcmp(_filter_string, text) == 0) + return; + + if (strlen(text) == 0) { + memset(_filter_string, 0, sizeof(_filter_string)); + } + else { + memset(_filter_string, 0, sizeof(_filter_string)); + strcpy(_filter_string, text); + } + + filter_update_counts(); + + w->scrolls->v_top = 0; + + window_invalidate(w); +} + +static bool filter_string(rct_object_entry *entry) +{ + if (_filter_string[0] == 0) + return true; + + char *name = object_get_name(entry); + if (name[0] == 0) + return false; + + char name_lower[MAX_PATH]; + char filter_lower[sizeof(_filter_string)]; + strcpy(name_lower, name); + strcpy(filter_lower, _filter_string); + + for (int i = 0; i < (int)strlen(name_lower); i++) + name_lower[i] = (char)tolower(name_lower[i]); + for (int i = 0; i < (int)strlen(filter_lower); i++) + filter_lower[i] = (char)tolower(filter_lower[i]); + + return strstr(name_lower, filter_lower) != NULL; +} + +static bool filter_source(rct_object_entry *entry) +{ + if (_FILTER_ALL) + return true; + + uint8 source = (entry->flags & 0xF0) >> 4; + return (_FILTER_RCT2 && source == 8) || (_FILTER_WW && source == 1) || (_FILTER_TT && source == 2) || (_FILTER_CUSTOM && source != 8 && source != 1 && source != 2); +} + +static bool filter_chunks(rct_object_entry *entry, rct_object_filters *filter) +{ + switch (entry->flags & 0x0F) { + case OBJECT_TYPE_RIDE: + if (_filter_flags & (1 << (filter->ride.category[0] + 5))) + return true; + if (_filter_flags & (1 << (filter->ride.category[1] + 5))) + return true; + + return false; + } + return true; +} + +static void filter_update_counts() +{ + if (!_FILTER_ALL || strlen(_filter_string) > 0) { + rct_object_entry *installed_entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + rct_object_filters *filter; + uint8 type; + for (int i = 0; i < 11; i++) { + _filter_object_counts[i] = 0; + } + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i) { + filter = get_object_filter(RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) - i); + type = installed_entry->flags & 0xF; + if (filter_source(installed_entry) && filter_string(installed_entry) && filter_chunks(installed_entry, filter)) { + _filter_object_counts[type]++; + } + installed_entry = object_get_next(installed_entry); + } + } +} diff --git a/src/windows/editor_objective_options.c b/src/windows/editor_objective_options.c index 9eb591219d..52071d8287 100644 --- a/src/windows/editor_objective_options.c +++ b/src/windows/editor_objective_options.c @@ -19,6 +19,229 @@ *****************************************************************************/ #include "../addresses.h" +#include "../game.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../scenario.h" +#include "../world/park.h" +#include "dropdown.h" +#include "error.h" +#include "../interface/themes.h" + +#define DISABLE_SIX_FLAGS_CHECKBOX + +#pragma region Widgets + +enum { + WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN, + WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_RIDES, + WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_COUNT +}; + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PAGE_BACKGROUND, + WIDX_TAB_1, + WIDX_TAB_2, + + WIDX_OBJECTIVE = 6, + WIDX_OBJECTIVE_DROPDOWN, + WIDX_OBJECTIVE_ARG_1, + WIDX_OBJECTIVE_ARG_1_INCREASE, + WIDX_OBJECTIVE_ARG_1_DECREASE, + WIDX_OBJECTIVE_ARG_2, + WIDX_OBJECTIVE_ARG_2_INCREASE, + WIDX_OBJECTIVE_ARG_2_DECREASE, + WIDX_CLIMATE, + WIDX_CLIMATE_DROPDOWN, + WIDX_PARK_NAME, + WIDX_SCENARIO_NAME, + WIDX_CATEGORY, + WIDX_CATEGORY_DROPDOWN, + WIDX_DETAILS, + WIDX_SIX_FLAGS, + + WIDX_RIDES = 6 +}; + +static rct_widget window_editor_objective_options_main_widgets[] = { + { WWT_FRAME, 0, 0, 449, 0, 228, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 448, 1, 14, STR_OBJECTIVE_SELECTION, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 437, 447, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 279, 43, 148, STR_NONE, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_SELECT_OBJECTIVE_AND_PARK_NAME_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_SELECT_RIDES_TO_BE_PRESERVED_TIP }, + { WWT_DROPDOWN, 1, 98, 441, 48, 59, STR_NONE, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 430, 440, 49, 58, STR_DROPDOWN_GLYPH, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP }, + { WWT_SPINNER, 1, 158, 237, 65, 76, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 226, 236, 66, 70, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 226, 236, 71, 75, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 158, 277, 82, 93, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 266, 276, 83, 87, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 266, 276, 88, 92, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_DROPDOWN, 1, 98, 277, 99, 110, STR_NONE, STR_SELECT_CLIMATE_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 266, 276, 100, 109, STR_DROPDOWN_GLYPH, STR_SELECT_CLIMATE_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 370, 444, 116, 127, STR_CHANGE, STR_CHANGE_NAME_OF_PARK_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 370, 444, 133, 144, STR_CHANGE, STR_CHANGE_NAME_OF_SCENARIO_TIP }, + { WWT_DROPDOWN, 1, 98, 277, 150, 161, STR_NONE, STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN }, + { WWT_DROPDOWN_BUTTON, 1, 266, 276, 151, 160, STR_DROPDOWN_GLYPH, STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN }, + { WWT_DROPDOWN_BUTTON, 1, 370, 444, 167, 178, STR_CHANGE, STR_CHANGE_DETAIL_NOTES_ABOUT_PARK_SCENARIO_TIP }, + { WWT_CHECKBOX, 1, 8, 441, 215, 226, STR_SIX_FLAGS_PARK, STR_NONE }, + { WIDGETS_END } +}; + +static rct_widget window_editor_objective_options_rides_widgets[] = { + { WWT_FRAME, 0, 0, 449, 0, 228, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 448, 1, 14, STR_OBJECTIVE_SELECTION, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 437, 447, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 279, 43, 148, STR_NONE, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_SELECT_OBJECTIVE_AND_PARK_NAME_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_SELECT_RIDES_TO_BE_PRESERVED_TIP }, + { WWT_SCROLL, 1, 3, 376, 60, 220, 2, STR_NONE }, + { WIDGETS_END } +}; + +static rct_widget *window_editor_objective_options_widgets[] = { + window_editor_objective_options_main_widgets, + window_editor_objective_options_rides_widgets +}; + +#pragma endregion + +#pragma region Events + +static void window_editor_objective_options_emptysub() { } + +static void window_editor_objective_options_main_mouseup(); +static void window_editor_objective_options_main_resize(); +static void window_editor_objective_options_main_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_editor_objective_options_main_dropdown(); +static void window_editor_objective_options_main_update(rct_window *w); +static void window_editor_objective_options_main_textinput(); +static void window_editor_objective_options_main_invalidate(); +static void window_editor_objective_options_main_paint(); + +static void window_editor_objective_options_rides_mouseup(); +static void window_editor_objective_options_rides_resize(); +static void window_editor_objective_options_rides_update(rct_window *w); +static void window_editor_objective_options_rides_scrollgetheight(); +static void window_editor_objective_options_rides_scrollmousedown(); +static void window_editor_objective_options_rides_scrollmouseover(); +static void window_editor_objective_options_rides_invalidate(); +static void window_editor_objective_options_rides_paint(); +static void window_editor_objective_options_rides_scrollpaint(); + +// 0x009A9DF4 +static void* window_objective_options_main_events[] = { + window_editor_objective_options_emptysub, + window_editor_objective_options_main_mouseup, + window_editor_objective_options_main_resize, + window_editor_objective_options_main_mousedown, + window_editor_objective_options_main_dropdown, + window_editor_objective_options_emptysub, + window_editor_objective_options_main_update, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_main_textinput, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_main_invalidate, + window_editor_objective_options_main_paint, + window_editor_objective_options_emptysub +}; + +// 0x009A9F58 +static void* window_objective_options_rides_events[] = { + window_editor_objective_options_emptysub, + window_editor_objective_options_rides_mouseup, + window_editor_objective_options_rides_resize, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_rides_update, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_rides_scrollgetheight, + window_editor_objective_options_rides_scrollmousedown, + window_editor_objective_options_emptysub, + window_editor_objective_options_rides_scrollmouseover, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_emptysub, + window_editor_objective_options_rides_invalidate, + window_editor_objective_options_rides_paint, + window_editor_objective_options_rides_scrollpaint +}; + +static void* window_editor_objective_options_page_events[] = { + window_objective_options_main_events, + window_objective_options_rides_events +}; + +#pragma endregion + +#pragma region Enabled widgets + +static uint64 window_editor_objective_options_page_enabled_widgets[] = { + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_OBJECTIVE) | + (1 << WIDX_OBJECTIVE_DROPDOWN) | + (1 << WIDX_OBJECTIVE_ARG_1_INCREASE) | + (1 << WIDX_OBJECTIVE_ARG_1_DECREASE) | + (1 << WIDX_OBJECTIVE_ARG_2_INCREASE) | + (1 << WIDX_OBJECTIVE_ARG_2_DECREASE) | + (1 << WIDX_CLIMATE) | + (1 << WIDX_CLIMATE_DROPDOWN) | + (1 << WIDX_PARK_NAME) | + (1 << WIDX_SCENARIO_NAME) | + (1 << WIDX_CATEGORY) | + (1 << WIDX_CATEGORY_DROPDOWN) | + (1 << WIDX_DETAILS) | + (1 << WIDX_SIX_FLAGS), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) +}; + +static uint64 window_editor_objective_options_page_hold_down_widgets[] = { + (1 << WIDX_OBJECTIVE_ARG_1_INCREASE) | + (1 << WIDX_OBJECTIVE_ARG_1_DECREASE) | + (1 << WIDX_OBJECTIVE_ARG_2_INCREASE) | + (1 << WIDX_OBJECTIVE_ARG_2_DECREASE), + + 0 +}; + +#pragma endregion /** * @@ -26,5 +249,1039 @@ */ void window_editor_objective_options_open() { - RCT2_CALLPROC_EBPSAFE(0x0067137D); + rct_window *w; + + w = window_bring_to_front_by_class(WC_EDTIOR_OBJECTIVE_OPTIONS); + if (w != NULL) + return; + + w = window_create_centred( + 450, + 228, + (uint32*)window_objective_options_main_events, + WC_EDTIOR_OBJECTIVE_OPTIONS, + WF_10 + ); + w->widgets = window_editor_objective_options_main_widgets; + w->enabled_widgets = window_editor_objective_options_page_enabled_widgets[WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN]; + w->pressed_widgets = 0; + w->hold_down_widgets = window_editor_objective_options_page_hold_down_widgets[WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN]; + window_init_scroll_widgets(w); + w->var_4AE = 0; + w->selected_tab = WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN; + w->no_list_items = 0; + w->selected_list_item = -1; + RCT2_CALLPROC_X(0x00672609, 0, 0, 0, 0, (int)w, 0, 0); +} + +static void window_editor_objective_options_set_pressed_tab(rct_window *w) +{ + int i; + for (i = 0; i < 2; i++) + w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); +} + +static void window_editor_objective_options_anchor_border_widgets(rct_window *w) +{ + w->widgets[WIDX_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_TITLE].right = w->width - 2; + w->widgets[WIDX_CLOSE].left = w->width - 13; + w->widgets[WIDX_CLOSE].right = w->width - 3; +} + +static void window_editor_objective_options_draw_tab_images(rct_window *w, rct_drawpixelinfo *dpi) +{ + rct_widget *widget; + int spriteIndex; + + // Tab 1 + widget = &w->widgets[WIDX_TAB_1]; + + spriteIndex = 5511; + if (w->page == WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN) + spriteIndex += (w->frame_no / 4) % 16; + + gfx_draw_sprite(dpi, spriteIndex, w->x + widget->left, w->y + widget->top, 0); + + // Tab 2 + if (!(w->disabled_widgets & (1 << WIDX_TAB_2))) { + widget = &w->widgets[WIDX_TAB_2]; + spriteIndex = 5442; + if (w->page == WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_RIDES) + spriteIndex += (w->frame_no / 4) % 16; + + gfx_draw_sprite(dpi, spriteIndex, w->x + widget->left, w->y + widget->top, 0); + } +} + +/** + * + * rct2: 0x00668496 + */ +static void window_editor_objective_options_set_page(rct_window *w, int page) +{ + if (w->page == page) + return; + + w->page = page; + w->frame_no = 0; + w->var_492 = 0; + w->no_list_items = 0; + w->selected_list_item = -1; + w->enabled_widgets = window_editor_objective_options_page_enabled_widgets[page]; + w->hold_down_widgets = window_editor_objective_options_page_hold_down_widgets[page]; + w->event_handlers = window_editor_objective_options_page_events[page]; + w->widgets = window_editor_objective_options_widgets[page]; + window_invalidate(w); + RCT2_CALLPROC_X(0x00672609, 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); + window_event_invalidate_call(w); + window_init_scroll_widgets(w); + window_invalidate(w); +} + +/** + * + * rct2: 0x0067201D + */ +static void window_editor_objective_options_set_objective(rct_window *w, int objective) +{ + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) = objective; + window_invalidate(w); + + // Set default objective arguments + switch (objective) { + case OBJECTIVE_NONE: + case OBJECTIVE_HAVE_FUN: + case OBJECTIVE_BUILD_THE_BEST: + case OBJECTIVE_10_ROLLERCOASTERS: + break; + case OBJECTIVE_GUESTS_BY: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) = 3; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) = 1500; + break; + case OBJECTIVE_PARK_VALUE_BY: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) = 3; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) = MONEY(50000,00); + break; + case OBJECTIVE_GUESTS_AND_RATING: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) = 2000; + break; + case OBJECTIVE_MONTHLY_RIDE_INCOME: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) = MONEY(10000,00); + break; + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) = 1200; + break; + case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) = FIXED_2DP(6,70); + break; + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) = MONEY(50000,00); + break; + case OBJECTIVE_MONTHLY_FOOD_INCOME: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) = MONEY(1000,00); + break; + } +} + +/** + * + * rct2: 0x006719CA + */ +static void window_editor_objective_options_main_mouseup() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + window_editor_objective_options_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_PARK_NAME: + RCT2_GLOBAL(0x013CE962, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + window_text_input_open(w, WIDX_PARK_NAME, STR_PARK_NAME, STR_ENTER_PARK_NAME, RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id), 0, 32); + break; + case WIDX_SCENARIO_NAME: + strcpy((char*)0x009BC677, s6Info->name); + window_text_input_open(w, WIDX_SCENARIO_NAME, 3313, 3314, 3165, 0, 32); + break; + case WIDX_DETAILS: + strcpy((char*)0x009BC677, s6Info->details); + window_text_input_open(w, WIDX_DETAILS, 3315, 3316, 3165, 0, 256); + break; + case WIDX_SIX_FLAGS: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_SIX_FLAGS; + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x00672254 + */ +static void window_editor_objective_options_main_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 450, 229, 450, 229); +} + +static void window_editor_objective_options_show_objective_dropdown(rct_window *w) +{ + int i, numItems, objectiveType; + rct_widget *dropdownWidget; + uint32 parkFlags; + + dropdownWidget = &w->widgets[WIDX_OBJECTIVE]; + parkFlags = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); + numItems = 0; + + if (!(parkFlags & PARK_FLAGS_NO_MONEY_SCENARIO)) { + numItems += 2; + if (parkFlags & PARK_FLAGS_PARK_FREE_ENTRY) + numItems++; + } + + numItems += 5; + + i = 0; + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_HAVE_FUN; + i++; + + if (!(parkFlags & PARK_FLAGS_NO_MONEY_SCENARIO)) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_NUMBER_OF_GUESTS_AT_A_GIVEN_DATE; + i++; + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_MONTHLY_PROFIT_FROM_FOOD_MERCHANDISE; + i++; + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_REPAY_LOAN_AND_ACHIEVE_A_GIVEN_PARK_VALUE; + i++; + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_PARK_VALUE_AT_A_GIVEN_DATE; + i++; + if (parkFlags & PARK_FLAGS_PARK_FREE_ENTRY) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_MONTHLY_INCOME_FROM_RIDE_TICKETS; + i++; + } + } + + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_NUMBER_OF_GUESTS_IN_PARK; + i++; + + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_BUILD_10_ROLLER_COASTERS; + i++; + + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_BUILD_10_ROLLER_COASTERS_OF_A_GIVEN_LENGTH; + i++; + + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_OBJECTIVE_DROPDOWN_FINISH_BUILDING_5_ROLLER_COASTERS; + i++; + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + numItems, + dropdownWidget->right - dropdownWidget->left - 3 + ); + + objectiveType = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8); + for (i = 0; i < numItems; i++) { + if (gDropdownItemsArgs[i] - STR_OBJECTIVE_DROPDOWN_NONE == objectiveType) { + gDropdownItemsChecked = (1 << i); + break; + } + } +} + +static void window_editor_objective_options_show_climate_dropdown(rct_window *w) +{ + int i; + rct_widget *dropdownWidget; + + dropdownWidget = &w->widgets[WIDX_CLIMATE]; + + for (i = 0; i < 4; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_CLIMATE_COOL_AND_WET + i; + } + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + 4, + dropdownWidget->right - dropdownWidget->left - 3 + ); + gDropdownItemsChecked = (1 << RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8)); +} + +static void window_editor_objective_options_show_category_dropdown(rct_window *w) +{ + rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; + int i; + rct_widget *dropdownWidget; + + dropdownWidget = &w->widgets[WIDX_CATEGORY]; + + for (i = 0; i < 5; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_BEGINNER_PARKS + i; + } + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + 5, + dropdownWidget->right - dropdownWidget->left - 3 + ); + gDropdownItemsChecked = (1 << s6Info->category); +} + +static void window_editor_objective_options_arg_1_increase(rct_window *w) +{ + switch (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8)) { + case OBJECTIVE_PARK_VALUE_BY: + case OBJECTIVE_MONTHLY_RIDE_INCOME: + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) >= MONEY(2000000,00)) { + window_error_open(3264, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) += MONEY(1000,0); + window_invalidate(w); + } + break; + case OBJECTIVE_MONTHLY_FOOD_INCOME: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) >= MONEY(2000000,00)) { + window_error_open(3264, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) += MONEY(100,0); + window_invalidate(w); + } + break; + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) >= 5000) { + window_error_open(3264, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) += 100; + window_invalidate(w); + } + break; + case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) >= FIXED_2DP(9,90)) { + window_error_open(3264, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) += FIXED_2DP(0,10); + window_invalidate(w); + } + break; + default: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) >= 5000) { + window_error_open(3264, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) += 100; + window_invalidate(w); + } + break; + } +} + +static void window_editor_objective_options_arg_1_decrease(rct_window *w) +{ + switch (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8)) { + case OBJECTIVE_PARK_VALUE_BY: + case OBJECTIVE_MONTHLY_RIDE_INCOME: + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) <= MONEY(1000,00)) { + window_error_open(3265, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) -= MONEY(1000,0); + window_invalidate(w); + } + break; + case OBJECTIVE_MONTHLY_FOOD_INCOME: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) <= MONEY(1000,00)) { + window_error_open(3265, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) -= MONEY(100,0); + window_invalidate(w); + } + break; + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) <= 1000) { + window_error_open(3265, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) -= 100; + window_invalidate(w); + } + break; + case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) <= FIXED_2DP(4,00)) { + window_error_open(3265, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32) -= FIXED_2DP(0,10); + window_invalidate(w); + } + break; + default: + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) <= 500) { + window_error_open(3265, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) -= 100; + window_invalidate(w); + } + break; + } +} + +static void window_editor_objective_options_arg_2_increase(rct_window *w) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) >= 25) { + window_error_open(3264, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8)++; + window_invalidate(w); + } +} + +static void window_editor_objective_options_arg_2_decrease(rct_window *w) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) <= 1) { + window_error_open(3265, STR_NONE); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8)--; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x00671A0D + */ +static void window_editor_objective_options_main_mousedown(int widgetIndex, rct_window *w, rct_widget* widget) +{ + switch (widgetIndex) { + case WIDX_OBJECTIVE_DROPDOWN: + window_editor_objective_options_show_objective_dropdown(w); + break; + case WIDX_OBJECTIVE_ARG_1_INCREASE: + window_editor_objective_options_arg_1_increase(w); + break; + case WIDX_OBJECTIVE_ARG_1_DECREASE: + window_editor_objective_options_arg_1_decrease(w); + break; + case WIDX_OBJECTIVE_ARG_2_INCREASE: + window_editor_objective_options_arg_2_increase(w); + break; + case WIDX_OBJECTIVE_ARG_2_DECREASE: + window_editor_objective_options_arg_2_decrease(w); + break; + case WIDX_CLIMATE_DROPDOWN: + window_editor_objective_options_show_climate_dropdown(w); + break; + case WIDX_CATEGORY_DROPDOWN: + window_editor_objective_options_show_category_dropdown(w); + break; + } +} + +/** + * + * rct2: 0x00671A54 + */ +static void window_editor_objective_options_main_dropdown() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; + rct_window *w; + short widgetIndex, dropdownIndex; + uint8 newObjectiveType; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (dropdownIndex == -1) + return; + + switch (widgetIndex) { + case WIDX_OBJECTIVE_DROPDOWN: + newObjectiveType = (uint8)(gDropdownItemsArgs[dropdownIndex] - 2397); + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) != newObjectiveType) + window_editor_objective_options_set_objective(w, newObjectiveType); + break; + case WIDX_CLIMATE_DROPDOWN: + if (RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8) != (uint8)dropdownIndex) { + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8) = (uint8)dropdownIndex; + window_invalidate(w); + } + break; + case WIDX_CATEGORY_DROPDOWN: + if (s6Info->category != (uint8)dropdownIndex) { + s6Info->category = (uint8)dropdownIndex; + window_invalidate(w); + } + break; + } +} + +/** + * + * rct2: 0x006721E7 + */ +static void window_editor_objective_options_main_update(rct_window *w) +{ + uint32 parkFlags; + uint8 objectiveType; + + w->frame_no++; + window_event_invalidate_call(w); + widget_invalidate(w, WIDX_TAB_1); + + parkFlags = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); + objectiveType = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8); + + // Reset objective if invalid + if (( + (parkFlags & PARK_FLAGS_NO_MONEY_SCENARIO) && + + // The following objectives are the only valid objectives when there is no money + objectiveType != OBJECTIVE_HAVE_FUN && + objectiveType != OBJECTIVE_10_ROLLERCOASTERS && + objectiveType != OBJECTIVE_GUESTS_AND_RATING && + objectiveType != OBJECTIVE_10_ROLLERCOASTERS_LENGTH && + objectiveType != OBJECTIVE_FINISH_5_ROLLERCOASTERS + ) || ( + // The park must be free for the monthly ride income objective + !(parkFlags & PARK_FLAGS_PARK_FREE_ENTRY) && + objectiveType == OBJECTIVE_MONTHLY_RIDE_INCOME + )) { + // Reset objective + window_editor_objective_options_set_objective(w, OBJECTIVE_GUESTS_AND_RATING); + } +} + +/** + * + * rct2: 0x00671A73 + */ +static void window_editor_objective_options_main_textinput() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (!result) + return; + + switch (widgetIndex) { + case WIDX_PARK_NAME: + park_set_name(text); + + if (s6Info->name[0] == 0) + format_string(s6Info->name, RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id), (void*)RCT2_ADDRESS_PARK_NAME_ARGS); + break; + case WIDX_SCENARIO_NAME: + strncpy(s6Info->name, text, 64); + window_invalidate(w); + break; + case WIDX_DETAILS: + strncpy(s6Info->details, text, 256); + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x0067161C + */ +static void window_editor_objective_options_main_invalidate() +{ + rct_window *w; + rct_widget *widgets; + rct_stex_entry *stex; + + window_get_register(w); + colour_scheme_update(w); + + stex = g_stexEntries[0]; + if (stex == (rct_stex_entry*)0xFFFFFFFF) + stex = NULL; + + widgets = window_editor_objective_options_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_editor_objective_options_set_pressed_tab(w); + + // This options was only available in development version +#ifdef DISABLE_SIX_FLAGS_CHECKBOX + window_editor_objective_options_main_widgets[WIDX_SIX_FLAGS].type = WWT_EMPTY; +#endif + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SIX_FLAGS) + w->pressed_widgets |= (1 << WIDX_SIX_FLAGS); + else + w->pressed_widgets &= ~(1 << WIDX_SIX_FLAGS); + + if (stex == NULL) + w->disabled_widgets &= ~(WIDX_PARK_NAME | WIDX_SCENARIO_NAME); + else + w->disabled_widgets |= (WIDX_PARK_NAME | WIDX_SCENARIO_NAME); + + switch (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8)) { + case OBJECTIVE_GUESTS_BY: + case OBJECTIVE_PARK_VALUE_BY: + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WWT_SPINNER; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WWT_DROPDOWN_BUTTON; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WWT_SPINNER; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WWT_DROPDOWN_BUTTON; + break; + case OBJECTIVE_GUESTS_AND_RATING: + case OBJECTIVE_MONTHLY_RIDE_INCOME: + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + case OBJECTIVE_FINISH_5_ROLLERCOASTERS: + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + case OBJECTIVE_MONTHLY_FOOD_INCOME: + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WWT_SPINNER; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WWT_DROPDOWN_BUTTON; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WWT_EMPTY; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WWT_EMPTY; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WWT_EMPTY; + break; + default: + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WWT_EMPTY; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WWT_EMPTY; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WWT_EMPTY; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WWT_EMPTY; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WWT_EMPTY; + window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WWT_EMPTY; + break; + } + + window_editor_objective_options_main_widgets[WIDX_CLOSE].type = + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR ? WWT_EMPTY : WWT_CLOSEBOX; + + window_editor_objective_options_anchor_border_widgets(w); +} + +/** + * + * rct2: 0x0067161C + */ +static void window_editor_objective_options_main_paint() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; + rct_stex_entry *stex; + rct_window *w; + rct_drawpixelinfo *dpi; + int x, y, width; + rct_string_id stringId; + uint32 arg; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_editor_objective_options_draw_tab_images(w, dpi); + + stex = g_stexEntries[0]; + if (stex == (rct_stex_entry*)0xFFFFFFFF) + stex = NULL; + + // Objective label + x = w->x + 8; + y = w->y + w->widgets[WIDX_OBJECTIVE].top; + gfx_draw_string_left(dpi, 3287, NULL, 0, x, y); + + // Objective value + x = w->x + w->widgets[WIDX_OBJECTIVE].left + 1; + y = w->y + w->widgets[WIDX_OBJECTIVE].top; + stringId = STR_OBJECTIVE_2_NONE + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8); + gfx_draw_string_left(dpi, 1193, &stringId, 0, x, y); + + if (w->widgets[WIDX_OBJECTIVE_ARG_1].type != WWT_EMPTY) { + // Objective argument 1 label + x = w->x + 28; + y = w->y + w->widgets[WIDX_OBJECTIVE_ARG_1].top; + switch (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8)) { + case OBJECTIVE_GUESTS_BY: + case OBJECTIVE_GUESTS_AND_RATING: + stringId = 3303; + break; + case OBJECTIVE_PARK_VALUE_BY: + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + stringId = 3304; + break; + case OBJECTIVE_MONTHLY_RIDE_INCOME: + stringId = 3305; + break; + case OBJECTIVE_MONTHLY_FOOD_INCOME: + stringId = 3306; + break; + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + stringId = 3307; + break; + default: + stringId = 3308; + break; + } + gfx_draw_string_left(dpi, stringId, NULL, 0, x, y); + + // Objective argument 1 value + x = w->x + w->widgets[WIDX_OBJECTIVE_ARG_1].left + 1; + y = w->y + w->widgets[WIDX_OBJECTIVE_ARG_1].top; + switch (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8)) { + case OBJECTIVE_GUESTS_BY: + case OBJECTIVE_GUESTS_AND_RATING: + stringId = 3309; + arg = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); + break; + case OBJECTIVE_PARK_VALUE_BY: + case OBJECTIVE_REPLAY_LOAN_AND_PARK_VALUE: + case OBJECTIVE_MONTHLY_RIDE_INCOME: + case OBJECTIVE_MONTHLY_FOOD_INCOME: + stringId = 3246; + arg = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32); + break; + case OBJECTIVE_10_ROLLERCOASTERS_LENGTH: + stringId = 3310; + arg = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); + break; + default: + stringId = 3311; + arg = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, money32); + break; + } + gfx_draw_string_left(dpi, stringId, &arg, 0, x, y); + } + + if (w->widgets[WIDX_OBJECTIVE_ARG_2].type != WWT_EMPTY) { + // Objective argument 2 label + x = w->x + 28; + y = w->y + w->widgets[WIDX_OBJECTIVE_ARG_2].top; + gfx_draw_string_left(dpi, 3301, NULL, 0, x, y); + + // Objective argument 2 value + x = w->x + w->widgets[WIDX_OBJECTIVE_ARG_2].left + 1; + y = w->y + w->widgets[WIDX_OBJECTIVE_ARG_2].top; + arg = (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8) * MONTH_COUNT) - 1; + gfx_draw_string_left(dpi, 3302, &arg, 0, x, y); + } + + // Climate label + x = w->x + 8; + y = w->y + w->widgets[WIDX_CLIMATE].top; + gfx_draw_string_left(dpi, 3289, NULL, 0, x, y); + + // Climate value + x = w->x + w->widgets[WIDX_CLIMATE].left + 1; + y = w->y + w->widgets[WIDX_CLIMATE].top; + stringId = STR_CLIMATE_COOL_AND_WET + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8); + gfx_draw_string_left(dpi, 1193, &stringId, 0, x, y); + + // Park name + x = w->x + 8; + y = w->y + w->widgets[WIDX_PARK_NAME].top; + width = w->widgets[WIDX_PARK_NAME].left - 16; + + if (stex != NULL) { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = stex->park_name; + } else { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + } + RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x0013573D8, uint32); + gfx_draw_string_left_clipped(dpi, 3298, (void*)0x013CE952, 0, x, y, width); + + // Scenario name + x = w->x + 8; + y = w->y + w->widgets[WIDX_SCENARIO_NAME].top; + width = w->widgets[WIDX_SCENARIO_NAME].left - 16; + + if (stex != NULL) { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = stex->scenario_name; + } else { + strcpy((char*)0x009BC677, s6Info->name); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = 3165; + } + RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x0013573D8, uint32); + gfx_draw_string_left_clipped(dpi, 3300, (void*)0x013CE952, 0, x, y, width); + + // Scenario details label + x = w->x + 8; + y = w->y + w->widgets[WIDX_DETAILS].top; + gfx_draw_string_left(dpi, 3299, NULL, 0, x, y); + + // Scenario details value + x = w->x + 16; + y = w->y + w->widgets[WIDX_DETAILS].top + 10; + width = w->widgets[WIDX_DETAILS].left - 4; + + if (stex != NULL) { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = stex->details; + } else { + strcpy((char*)0x009BC677, s6Info->details); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = 3165; + } + RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x0013573D8, uint32); + gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, width, 1191, 0); + + // Scenario category label + x = w->x + 8; + y = w->y + w->widgets[WIDX_CATEGORY].top; + gfx_draw_string_left(dpi, 3319, NULL, 0, x, y); + + // Scenario category value + x = w->x + w->widgets[WIDX_CATEGORY].left + 1; + y = w->y + w->widgets[WIDX_CATEGORY].top; + stringId = STR_BEGINNER_PARKS + s6Info->category; + gfx_draw_string_left(dpi, 1193, &stringId, 0, x, y); +} + +/** + * + * rct2: 0x006724A4 + */ +static void window_editor_objective_options_rides_mouseup() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + window_editor_objective_options_set_page(w, widgetIndex - WIDX_TAB_1); + break; + } +} + +/** + * + * rct2: 0x006725A8 + */ +static void window_editor_objective_options_rides_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 380, 224, 380, 224); +} + +/** + * + * rct2: 0x00672544 + */ +static void window_editor_objective_options_rides_update(rct_window *w) +{ + int i, numItems; + rct_ride *ride; + + w->frame_no++; + window_event_invalidate_call(w); + window_event_resize_call(w); + widget_invalidate(w, WIDX_TAB_2); + + numItems = 0; + FOR_ALL_RIDES(i, ride) { + if (gRideClassifications[ride->type] == RIDE_CLASS_RIDE) { + w->list_item_positions[numItems] = i; + numItems++; + } + } + + if (w->no_list_items != numItems) { + w->no_list_items = numItems; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006724BF + */ +static void window_editor_objective_options_rides_scrollgetheight() +{ + int width, height; + rct_window *w; + + window_get_register(w); + + width = 0; + height = w->no_list_items * 12; + + window_scrollsize_set_registers(width, height); +} + +/** + * + * rct2: 0x006724FC + */ +static void window_editor_objective_options_rides_scrollmousedown() +{ + rct_ride *ride; + rct_window *w; + short x, y, scrollIndex; + int i; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + i = y / 12; + if (i < 0 || i >= w->no_list_items) + return; + + ride = GET_RIDE(i); + ride->lifecycle_flags ^= RIDE_LIFECYCLE_INDESTRUCTIBLE; + window_invalidate(w); +} + +/** + * + * rct2: 0x006724CC + */ +static void window_editor_objective_options_rides_scrollmouseover() +{ + rct_window *w; + short x, y, scrollIndex; + int i; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + i = y / 12; + if (i < 0 || i >= w->no_list_items) + return; + + if (w->selected_list_item != i) { + w->selected_list_item = i; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006722B5 + */ +static void window_editor_objective_options_rides_invalidate() +{ + rct_window *w; + rct_widget *widgets; + + window_get_register(w); + colour_scheme_update(w); + + widgets = window_editor_objective_options_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_editor_objective_options_set_pressed_tab(w); + + window_editor_objective_options_main_widgets[WIDX_CLOSE].type = + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR ? WWT_EMPTY : WWT_CLOSEBOX; + + window_editor_objective_options_anchor_border_widgets(w); +} + +/** + * + * rct2: 0x00672340 + */ +static void window_editor_objective_options_rides_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_editor_objective_options_draw_tab_images(w, dpi); + + gfx_draw_string_left(dpi, 3312, NULL, 0, w->x + 6, w->y + w->widgets[WIDX_PAGE_BACKGROUND].top + 3); +} + +/** + * + * rct2: 0x0067236F + */ +static void window_editor_objective_options_rides_scrollpaint() +{ + int i, y, colour; + rct_string_id stringId; + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + + window_paint_get_registers(w, dpi); + + colour = RCT2_GLOBAL(0x0141FC48 + (w->colours[1] * 8), uint8); + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, colour); + + for (i = 0; i < w->no_list_items; i++) { + y = i * 12; + + if (y + 12 < dpi->y || y >= dpi->y + dpi->height) + continue; + + // Checkbox + gfx_fill_rect_inset(dpi, 2, y, 11, y + 10, w->colours[1], 224); + + // Highlighted + if (i == w->selected_list_item) { + stringId = 1193; + gfx_fill_rect(dpi, 0, y, w->width, y + 11, 0x2000031); + } else { + stringId = 1191; + } + + // Checkbox mark + ride = GET_RIDE(i); + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = stringId == 1193 ? 0xFFFE : 0xFFFF; + gfx_draw_string(dpi, (char*)0x009DED72, w->colours[1] & 0x7F, 2, y); + } + + // Ride name + gfx_draw_string_left(dpi, stringId, &ride->name, 0, 15, y); + } } \ No newline at end of file diff --git a/src/windows/editor_scenario_options.c b/src/windows/editor_scenario_options.c index 2157d3565f..1dea670bd6 100644 --- a/src/windows/editor_scenario_options.c +++ b/src/windows/editor_scenario_options.c @@ -19,6 +19,314 @@ *****************************************************************************/ #include "../addresses.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../management/finance.h" +#include "../sprites.h" +#include "error.h" +#include "dropdown.h" +#include "../interface/themes.h" + +#pragma region Widgets + +enum { + WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL, + WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_GUESTS, + WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_PARK, + WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_COUNT +}; + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PAGE_BACKGROUND, + WIDX_TAB_1, + WIDX_TAB_2, + WIDX_TAB_3, + + WIDX_NO_MONEY = 7, + WIDX_INITIAL_CASH, + WIDX_INITIAL_CASH_INCREASE, + WIDX_INITIAL_CASH_DECREASE, + WIDX_INITIAL_LOAN, + WIDX_INITIAL_LOAN_INCREASE, + WIDX_INITIAL_LOAN_DECREASE, + WIDX_MAXIMUM_LOAN, + WIDX_MAXIMUM_LOAN_INCREASE, + WIDX_MAXIMUM_LOAN_DECREASE, + WIDX_INTEREST_RATE, + WIDX_INTEREST_RATE_INCREASE, + WIDX_INTEREST_RATE_DECREASE, + WIDX_FORBID_MARKETING, + + WIDX_CASH_PER_GUEST = 7, + WIDX_CASH_PER_GUEST_INCREASE, + WIDX_CASH_PER_GUEST_DECREASE, + WIDX_GUEST_INITIAL_HAPPINESS, + WIDX_GUEST_INITIAL_HAPPINESS_INCREASE, + WIDX_GUEST_INITIAL_HAPPINESS_DECREASE, + WIDX_GUEST_INITIAL_HUNGER, + WIDX_GUEST_INITIAL_HUNGER_INCREASE, + WIDX_GUEST_INITIAL_HUNGER_DECREASE, + WIDX_GUEST_INITIAL_THIRST, + WIDX_GUEST_INITIAL_THIRST_INCREASE, + WIDX_GUEST_INITIAL_THIRST_DECREASE, + WIDX_GUEST_PREFER_LESS_INTENSE_RIDES, + WIDX_GUEST_PREFER_MORE_INTENSE_RIDES, + + WIDX_LAND_COST = 7, + WIDX_LAND_COST_INCREASE, + WIDX_LAND_COST_DECREASE, + WIDX_CONSTRUCTION_RIGHTS_COST, + WIDX_CONSTRUCTION_RIGHTS_COST_INCREASE, + WIDX_CONSTRUCTION_RIGHTS_COST_DECREASE, + WIDX_PAY_FOR_PARK_OR_RIDES, + WIDX_PAY_FOR_PARK_OR_RIDES_DROPDOWN, + WIDX_ENTRY_PRICE, + WIDX_ENTRY_PRICE_INCREASE, + WIDX_ENTRY_PRICE_DECREASE, + WIDX_FORBID_TREE_REMOVAL, + WIDX_FORBID_LANDSCAPE_CHANGES, + WIDX_FORBID_HIGH_CONSTRUCTION, + WIDX_HARD_PARK_RATING, + WIDX_HARD_GUEST_GENERATION +}; + +static rct_widget window_editor_scenario_options_financial_widgets[] = { + { WWT_FRAME, 0, 0, 279, 0, 148, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 278, 1, 14, STR_SCENARIO_OPTIONS_FINANCIAL, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 267, 277, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 279, 43, 148, STR_NONE, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_SCENARIO_OPTIONS_FINANCIAL_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_SCENARIO_OPTIONS_GUESTS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_SCENARIO_OPTIONS_PARK_TIP }, + + { WWT_CHECKBOX, 1, 8, 271, 48, 59, 3238, STR_MAKE_PARK_NO_MONEY_TIP }, + { WWT_SPINNER, 1, 168, 267, 65, 76, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 256, 266, 66, 70, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 256, 266, 71, 75, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 168, 267, 82, 93, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 256, 266, 83, 87, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 256, 266, 88, 92, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 168, 267, 99, 110, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 256, 266, 100, 104, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 256, 266, 105, 109, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 168, 237, 116, 127, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 226, 236, 117, 121, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 226, 236, 122, 126, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 8, 271, 133, 144, 3244, STR_FORBID_MARKETING_TIP }, + { WIDGETS_END } +}; + +static rct_widget window_editor_scenario_options_guests_widgets[] = { + { WWT_FRAME, 0, 0, 279, 0, 148, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 278, 1, 14, STR_SCENARIO_OPTIONS_GUESTS, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 267, 277, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 279, 43, 148, STR_NONE, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_SCENARIO_OPTIONS_FINANCIAL_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_SCENARIO_OPTIONS_GUESTS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_SCENARIO_OPTIONS_PARK_TIP }, + + { WWT_SPINNER, 1, 268, 337, 48, 59, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 49, 53, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 54, 58, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 268, 337, 65, 76, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 66, 70, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 71, 75, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 268, 337, 82, 93, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 83, 87, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 88, 92, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 268, 337, 99, 110, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 100, 104, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 326, 336, 105, 109, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 8, 371, 116, 127, STR_GUESTS_PREFER_LESS_INTENSE_RIDES, STR_GUESTS_PREFER_LESS_INTENSE_RIDES_TIP }, + { WWT_CHECKBOX, 1, 8, 371, 133, 144, STR_GUESTS_PREFER_MORE_INTENSE_RIDES, STR_GUESTS_PREFER_MORE_INTENSE_RIDES_TIP }, + { WIDGETS_END } +}; + +static rct_widget window_editor_scenario_options_park_widgets[] = { + { WWT_FRAME, 0, 0, 279, 0, 148, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 278, 1, 14, STR_SCENARIO_OPTIONS_PARK, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 267, 277, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 279, 43, 148, STR_NONE, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_SCENARIO_OPTIONS_FINANCIAL_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_SCENARIO_OPTIONS_GUESTS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_SCENARIO_OPTIONS_PARK_TIP }, + + { WWT_SPINNER, 1, 188, 257, 48, 59, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 246, 256, 49, 53, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 246, 256, 54, 58, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 188, 257, 65, 76, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 246, 256, 66, 70, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 246, 256, 71, 75, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_DROPDOWN, 1, 8, 217, 82, 93, STR_NONE, STR_PAY_FOR_PARK_PAY_FOR_RIDES_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 206, 216, 83, 92, STR_DROPDOWN_GLYPH, STR_PAY_FOR_PARK_PAY_FOR_RIDES_TIP }, + { WWT_SPINNER, 1, 328, 397, 82, 93, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 386, 396, 83, 87, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 386, 396, 88, 92, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 8, 391, 99, 110, STR_FORBID_TREE_REMOVAL, STR_FORBID_TREE_REMOVAL_TIP }, + { WWT_CHECKBOX, 1, 8, 391, 116, 127, STR_FORBID_LANDSCAPE_CHANGES, STR_FORBID_LANDSCAPE_CHANGES_TIP }, + { WWT_CHECKBOX, 1, 8, 391, 133, 144, STR_FORBID_HIGH_CONSTRUCTION, STR_FORBID_HIGH_CONSTRUCTION_TIP }, + { WWT_CHECKBOX, 1, 8, 391, 150, 161, STR_HARD_PARK_RATING, STR_HARD_PARK_RATING_TIP }, + { WWT_CHECKBOX, 1, 8, 391, 167, 178, STR_HARD_GUEST_GENERATION, STR_HARD_GUEST_GENERATION_TIP }, + { WIDGETS_END } +}; + +static rct_widget *window_editor_scenario_options_widgets[] = { + window_editor_scenario_options_financial_widgets, + window_editor_scenario_options_guests_widgets, + window_editor_scenario_options_park_widgets +}; + +#pragma endregion + +#pragma region Events + +static void window_editor_scenario_options_emptysub() { } + +static void window_editor_scenario_options_financial_mouseup(); +static void window_editor_scenario_options_financial_resize(); +static void window_editor_scenario_options_financial_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_editor_scenario_options_financial_update(rct_window *w); +static void window_editor_scenario_options_financial_invalidate(); +static void window_editor_scenario_options_financial_paint(); + +static void window_editor_scenario_options_guests_mouseup(); +static void window_editor_scenario_options_guests_resize(); +static void window_editor_scenario_options_guests_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_editor_scenario_options_guests_update(rct_window *w); +static void window_editor_scenario_options_guests_invalidate(); +static void window_editor_scenario_options_guests_paint(); + +static void window_editor_scenario_options_park_mouseup(); +static void window_editor_scenario_options_park_resize(); +static void window_editor_scenario_options_park_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_editor_scenario_options_park_dropdown(); +static void window_editor_scenario_options_park_update(rct_window *w); +static void window_editor_scenario_options_park_invalidate(); +static void window_editor_scenario_options_park_paint(); + +// 0x0097EB60 +static void* window_scenario_options_financial_events[] = { + window_editor_scenario_options_emptysub, + window_editor_scenario_options_financial_mouseup, + window_editor_scenario_options_financial_resize, + window_editor_scenario_options_financial_mousedown, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_financial_update, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_financial_invalidate, + window_editor_scenario_options_financial_paint, + window_editor_scenario_options_emptysub +}; + +// 0x0097EBD0 +static void* window_scenario_options_guests_events[] = { + window_editor_scenario_options_emptysub, + window_editor_scenario_options_guests_mouseup, + window_editor_scenario_options_guests_resize, + window_editor_scenario_options_guests_mousedown, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_guests_update, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_guests_invalidate, + window_editor_scenario_options_guests_paint, + window_editor_scenario_options_emptysub +}; + +// 0x0097EC40 +static void* window_scenario_options_park_events[] = { + window_editor_scenario_options_emptysub, + window_editor_scenario_options_park_mouseup, + window_editor_scenario_options_park_resize, + window_editor_scenario_options_park_mousedown, + window_editor_scenario_options_park_dropdown, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_park_update, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_emptysub, + window_editor_scenario_options_park_invalidate, + window_editor_scenario_options_park_paint, + window_editor_scenario_options_emptysub +}; + +static void* window_editor_scenario_options_page_events[] = { + window_scenario_options_financial_events, + window_scenario_options_guests_events, + window_scenario_options_park_events +}; + +#pragma endregion + +#pragma region Enabled widgets + +static uint64 window_editor_scenario_options_page_enabled_widgets[] = { + 0x001DB6F4, + 0x001EDB74, + 0x007F7B74 +}; + +static uint32 window_editor_scenario_options_page_hold_down_widgets[] = { + 0x000DB600, + 0x0006DB00, + 0x00031B00 +}; + +#pragma endregion /** * @@ -26,5 +334,908 @@ */ void window_editor_scenario_options_open() { - RCT2_CALLPROC_EBPSAFE(0x00670138); -} \ No newline at end of file + rct_window *w; + + w = window_bring_to_front_by_class(WC_EDITOR_SCENARIO_OPTIONS); + if (w != NULL) + return; + + w = window_create_centred( + 280, + 148, + window_editor_scenario_options_page_events[0], + WC_EDITOR_SCENARIO_OPTIONS, + WF_2 + ); + w->widgets = window_editor_scenario_options_widgets[0]; + w->enabled_widgets = window_editor_scenario_options_page_enabled_widgets[0]; + w->hold_down_widgets = window_editor_scenario_options_page_hold_down_widgets[0]; + window_init_scroll_widgets(w); + w->var_4AE = 0; + w->page = 0; +} + +static void window_editor_scenario_options_set_pressed_tab(rct_window *w) +{ + int i; + for (i = 0; i < WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_COUNT; i++) + w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); +} + +static void window_editor_scenario_options_anchor_border_widgets(rct_window *w) +{ + w->widgets[WIDX_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_TITLE].right = w->width - 2; + w->widgets[WIDX_CLOSE].left = w->width - 13; + w->widgets[WIDX_CLOSE].right = w->width - 3; +} + +/** + * + * rct2: 0x006712E8 + */ +static void window_editor_scenario_options_draw_tab_images(rct_window *w, rct_drawpixelinfo *dpi) +{ + rct_widget *widget; + int spriteIndex; + + // Tab 1 + widget = &w->widgets[WIDX_TAB_1]; + spriteIndex = SPR_TAB_FINANCES_SUMMARY_0; + if (w->page == WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL) + spriteIndex += (w->frame_no / 2) % 8; + + gfx_draw_sprite(dpi, spriteIndex, w->x + widget->left, w->y + widget->top, 0); + + // Tab 2 + widget = &w->widgets[WIDX_TAB_2]; + spriteIndex = SPR_TAB_GUESTS_0; + if (w->page == WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_GUESTS) + spriteIndex += (w->frame_no / 4) % 8; + + gfx_draw_sprite(dpi, spriteIndex, w->x + widget->left, w->y + widget->top, 0); + + // Tab 3 + widget = &w->widgets[WIDX_TAB_3]; + spriteIndex = STR_TAB_PARK; + gfx_draw_sprite(dpi, spriteIndex, w->x + widget->left, w->y + widget->top, 0); +} + +/** + * + * rct2: 0x00668496 + */ +static void window_editor_scenario_options_set_page(rct_window *w, int page) +{ + if (w->page == page) + return; + + w->page = page; + w->frame_no = 0; + w->var_492 = 0; + w->enabled_widgets = window_editor_scenario_options_page_enabled_widgets[page]; + w->hold_down_widgets = window_editor_scenario_options_page_hold_down_widgets[page]; + w->event_handlers = window_editor_scenario_options_page_events[page]; + w->widgets = window_editor_scenario_options_widgets[page]; + window_invalidate(w); + window_event_resize_call(w); + window_event_invalidate_call(w); + window_init_scroll_widgets(w); + window_invalidate(w); +} + +#pragma region Financial + +/** + * + * rct2: 0x0067049D + */ +static void window_editor_scenario_options_financial_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + window_editor_scenario_options_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_NO_MONEY: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_NO_MONEY_SCENARIO; + window_invalidate(w); + break; + case WIDX_FORBID_MARKETING: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_FORBID_MARKETING_CAMPAIGN; + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x0067077A + */ +static void window_editor_scenario_options_financial_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 280, 149, 280, 149); +} + +/** + * + * rct2: 0x006704C8 + */ +static void window_editor_scenario_options_financial_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + switch (widgetIndex) { + case WIDX_INITIAL_CASH_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) < MONEY(10000,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) += MONEY(500,00); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32) = ENCRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32)); + sub_69E869(); + } else { + window_error_open(3248, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_INITIAL_CASH_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) > MONEY(0,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) -= MONEY(500,00); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32) = ENCRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32)); + sub_69E869(); + } else { + window_error_open(3249, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_INITIAL_LOAN_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) < MONEY(5000000,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) += MONEY(1000,00); + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = max(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32), RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32)); + } else { + window_error_open(3250, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_INITIAL_LOAN_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) > MONEY(0,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) -= MONEY(1000,00); + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = max(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32), RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32)); + } else { + window_error_open(3251, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_MAXIMUM_LOAN_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) < MONEY(5000000,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) += MONEY(1000,00); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = min(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32), RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32)); + } else { + window_error_open(3252, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_MAXIMUM_LOAN_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) > MONEY(0,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) -= MONEY(1000,00); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = min(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32), RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32)); + } else { + window_error_open(3253, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_INTEREST_RATE_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32) < 80) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32)++; + } else { + window_error_open(3254, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_INTEREST_RATE_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32) > 5) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32)--; + } else { + window_error_open(3255, STR_NONE); + } + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x00670760 + */ +static void window_editor_scenario_options_financial_update(rct_window *w) +{ + w->frame_no++; + window_event_invalidate_call(w); + widget_invalidate(w, WIDX_TAB_1); +} + +/** + * + * rct2: 0x006701CF + */ +static void window_editor_scenario_options_financial_invalidate() +{ + rct_window *w; + rct_widget *widgets; + int i; + + window_get_register(w); + colour_scheme_update(w); + + widgets = window_editor_scenario_options_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_editor_scenario_options_set_pressed_tab(w); + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + w->pressed_widgets |= (1 << WIDX_NO_MONEY); + for (i = WIDX_INITIAL_CASH; i <= WIDX_FORBID_MARKETING; i++) + w->widgets[i].type = WWT_EMPTY; + } else { + w->pressed_widgets &= ~(1 << WIDX_NO_MONEY); + w->widgets[WIDX_INITIAL_CASH].type = WWT_SPINNER; + w->widgets[WIDX_INITIAL_CASH_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_INITIAL_CASH_DECREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_INITIAL_LOAN].type = WWT_SPINNER; + w->widgets[WIDX_INITIAL_LOAN_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_INITIAL_LOAN_DECREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_MAXIMUM_LOAN].type = WWT_SPINNER; + w->widgets[WIDX_MAXIMUM_LOAN_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_MAXIMUM_LOAN_DECREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_INTEREST_RATE].type = WWT_SPINNER; + w->widgets[WIDX_INTEREST_RATE_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_INTEREST_RATE_DECREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_FORBID_MARKETING].type = WWT_CHECKBOX; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) + w->pressed_widgets |= (1 << WIDX_FORBID_MARKETING); + else + w->pressed_widgets &= ~(1 << WIDX_FORBID_MARKETING); + + w->widgets[WIDX_CLOSE].type = + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR ? WWT_EMPTY : WWT_CLOSEBOX; + + window_editor_scenario_options_anchor_border_widgets(w); +} + +/** + * + * rct2: 0x00670338 + */ +static void window_editor_scenario_options_financial_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + int x, y; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_editor_scenario_options_draw_tab_images(w, dpi); + + if (w->widgets[WIDX_INITIAL_CASH].type != WWT_EMPTY) { + x = w->x + 8; + y = w->y + w->widgets[WIDX_INITIAL_CASH].top; + gfx_draw_string_left(dpi, 3240, NULL, 0, x, y); + + x = w->x + w->widgets[WIDX_INITIAL_CASH].left + 1; + y = w->y + w->widgets[WIDX_INITIAL_CASH].top; + gfx_draw_string_left(dpi, 3246, &RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32), 0, x, y); + } + + if (w->widgets[WIDX_INITIAL_LOAN].type != WWT_EMPTY) { + x = w->x + 8; + y = w->y + w->widgets[WIDX_INITIAL_LOAN].top; + gfx_draw_string_left(dpi, 3241, NULL, 0, x, y); + + x = w->x + w->widgets[WIDX_INITIAL_LOAN].left + 1; + y = w->y + w->widgets[WIDX_INITIAL_LOAN].top; + gfx_draw_string_left(dpi, 3246, &RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32), 0, x, y); + } + + if (w->widgets[WIDX_MAXIMUM_LOAN].type != WWT_EMPTY) { + x = w->x + 8; + y = w->y + w->widgets[WIDX_MAXIMUM_LOAN].top; + gfx_draw_string_left(dpi, 3242, NULL, 0, x, y); + + x = w->x + w->widgets[WIDX_MAXIMUM_LOAN].left + 1; + y = w->y + w->widgets[WIDX_MAXIMUM_LOAN].top; + gfx_draw_string_left(dpi, 3246, &RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32), 0, x, y); + } + + if (w->widgets[WIDX_INTEREST_RATE].type != WWT_EMPTY) { + x = w->x + 8; + y = w->y + w->widgets[WIDX_INTEREST_RATE].top; + gfx_draw_string_left(dpi, 3243, NULL, 0, x, y); + + x = w->x + w->widgets[WIDX_INTEREST_RATE].left + 1; + y = w->y + w->widgets[WIDX_INTEREST_RATE].top; + gfx_draw_string_left(dpi, 3247, &RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32), 0, x, y); + } +} + +#pragma endregion + +#pragma region Guests + +/** + * + * rct2: 0x00670A62 + */ +static void window_editor_scenario_options_guests_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + window_editor_scenario_options_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_GUEST_PREFER_LESS_INTENSE_RIDES: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_PREF_LESS_INTENSE_RIDES; + window_invalidate(w); + break; + case WIDX_GUEST_PREFER_MORE_INTENSE_RIDES: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_PREF_MORE_INTENSE_RIDES; + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x00670C59 + */ +static void window_editor_scenario_options_guests_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 380, 149, 380, 149); +} + +/** + * + * rct2: 0x00670A89 + */ +static void window_editor_scenario_options_guests_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + switch (widgetIndex) { + case WIDX_CASH_PER_GUEST_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) < MONEY(100, 00)) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) += MONEY(1, 00); + } else { + window_error_open(3264, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_CASH_PER_GUEST_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) > MONEY(0, 00)) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) -= MONEY(1, 00); + } else { + window_error_open(3265, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_GUEST_INITIAL_HAPPINESS_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) < 250) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) += 4; + } else { + window_error_open(3264, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_GUEST_INITIAL_HAPPINESS_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) > 40) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) -= 4; + } else { + window_error_open(3265, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_GUEST_INITIAL_HUNGER_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8) > 40) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8) -= 4; + } else { + window_error_open(3264, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_GUEST_INITIAL_HUNGER_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8) < 250) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8) += 4; + } else { + window_error_open(3265, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_GUEST_INITIAL_THIRST_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8) > 40) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8) -= 4; + } else { + window_error_open(3264, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_GUEST_INITIAL_THIRST_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8) < 250) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8) += 4; + } else { + window_error_open(3265, STR_NONE); + } + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x00670C3F + */ +static void window_editor_scenario_options_guests_update(rct_window *w) +{ + w->frame_no++; + window_event_invalidate_call(w); + widget_invalidate(w, WIDX_TAB_2); +} + +/** + * + * rct2: 0x006707DB + */ +static void window_editor_scenario_options_guests_invalidate() +{ + rct_window *w; + rct_widget *widgets; + + window_get_register(w); + colour_scheme_update(w); + + widgets = window_editor_scenario_options_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_editor_scenario_options_set_pressed_tab(w); + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + w->widgets[WIDX_CASH_PER_GUEST].type = WWT_EMPTY; + w->widgets[WIDX_CASH_PER_GUEST_INCREASE].type = WWT_EMPTY; + w->widgets[WIDX_CASH_PER_GUEST_DECREASE].type = WWT_EMPTY; + } else { + w->widgets[WIDX_CASH_PER_GUEST].type = WWT_SPINNER; + w->widgets[WIDX_CASH_PER_GUEST_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_CASH_PER_GUEST_DECREASE].type = WWT_DROPDOWN_BUTTON; + } + + // Guests prefer less intense rides checkbox + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_LESS_INTENSE_RIDES) + w->pressed_widgets |= (1 << WIDX_GUEST_PREFER_LESS_INTENSE_RIDES); + else + w->pressed_widgets &= ~(1 << WIDX_GUEST_PREFER_LESS_INTENSE_RIDES); + + // Guests prefer more intense rides checkbox + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) + w->pressed_widgets |= (1 << WIDX_GUEST_PREFER_MORE_INTENSE_RIDES); + else + w->pressed_widgets &= ~(1 << WIDX_GUEST_PREFER_MORE_INTENSE_RIDES); + + w->widgets[WIDX_CLOSE].type = + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR ? WWT_EMPTY : WWT_CLOSEBOX; + + window_editor_scenario_options_anchor_border_widgets(w); +} + +/** + * + * rct2: 0x006708C4 + */ +static void window_editor_scenario_options_guests_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + int x, y, arg; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_editor_scenario_options_draw_tab_images(w, dpi); + + if (w->widgets[WIDX_CASH_PER_GUEST].type != WWT_EMPTY) { + // Cash per guest label + x = w->x + 8; + y = w->y + w->widgets[WIDX_CASH_PER_GUEST].top; + gfx_draw_string_left(dpi, 3260, NULL, 0, x, y); + + // Cash per guest value + x = w->x + w->widgets[WIDX_CASH_PER_GUEST].left + 1; + y = w->y + w->widgets[WIDX_CASH_PER_GUEST].top; + arg = RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16); + gfx_draw_string_left(dpi, 3246, &arg, 0, x, y); + } + + // Guest initial happiness label + x = w->x + 8; + y = w->y + w->widgets[WIDX_GUEST_INITIAL_HAPPINESS].top; + gfx_draw_string_left(dpi, 3261, NULL, 0, x, y); + + // Guest initial happiness value + x = w->x + w->widgets[WIDX_GUEST_INITIAL_HAPPINESS].left + 1; + y = w->y + w->widgets[WIDX_GUEST_INITIAL_HAPPINESS].top; + arg = (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) * 100) / 255; + gfx_draw_string_left(dpi, 3247, &arg, 0, x, y); + + // Guest initial hunger label + x = w->x + 8; + y = w->y + w->widgets[WIDX_GUEST_INITIAL_HUNGER].top; + gfx_draw_string_left(dpi, 3262, NULL, 0, x, y); + + // Guest initial hunger value + x = w->x + w->widgets[WIDX_GUEST_INITIAL_HUNGER].left + 1; + y = w->y + w->widgets[WIDX_GUEST_INITIAL_HUNGER].top; + arg = ((255 - RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8)) * 100) / 255; + gfx_draw_string_left(dpi, 3247, &arg, 0, x, y); + + // Guest initial thirst label + x = w->x + 8; + y = w->y + w->widgets[WIDX_GUEST_INITIAL_THIRST].top; + gfx_draw_string_left(dpi, 3263, NULL, 0, x, y); + + // Guest initial thirst value + x = w->x + w->widgets[WIDX_GUEST_INITIAL_THIRST].left + 1; + y = w->y + w->widgets[WIDX_GUEST_INITIAL_THIRST].top; + arg = ((255 - RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8)) * 100) / 255; + gfx_draw_string_left(dpi, 3247, &arg, 0, x, y); +} + +#pragma endregion + +#pragma region Park + +/** + * + * rct2: 0x00670FD8 + */ +static void window_editor_scenario_options_park_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + window_editor_scenario_options_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_FORBID_TREE_REMOVAL: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_FORBID_TREE_REMOVAL; + window_invalidate(w); + break; + case WIDX_FORBID_LANDSCAPE_CHANGES: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_FORBID_LANDSCAPE_CHANGES; + window_invalidate(w); + break; + case WIDX_FORBID_HIGH_CONSTRUCTION: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_FORBID_HIGH_CONSTRUCTION; + window_invalidate(w); + break; + case WIDX_HARD_PARK_RATING: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_DIFFICULT_PARK_RATING; + window_invalidate(w); + break; + case WIDX_HARD_GUEST_GENERATION: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_DIFFICULT_GUEST_GENERATION; + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x00671287 + */ +static void window_editor_scenario_options_park_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 400, 183, 400, 183); +} + +/** + * + * rct2: 0x00671019 + */ +static void window_editor_scenario_options_park_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_widget *dropdownWidget; + + switch (widgetIndex) { + case WIDX_LAND_COST_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) < MONEY(200,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) += MONEY(1,00); + } else { + window_error_open(3264, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_LAND_COST_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) > MONEY(5,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) -= MONEY(1,00); + } else { + window_error_open(3265, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_CONSTRUCTION_RIGHTS_COST_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16) < MONEY(200,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16) += MONEY(1,00); + } else { + window_error_open(3264, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_CONSTRUCTION_RIGHTS_COST_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16) > MONEY(5,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16) -= MONEY(1,00); + } else { + window_error_open(3265, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_ENTRY_PRICE_INCREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) < MONEY(100,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) += MONEY(1,00); + } else { + window_error_open(3264, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_ENTRY_PRICE_DECREASE: + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) > MONEY(0,00)) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) -= MONEY(1,00); + } else { + window_error_open(3265, STR_NONE); + } + window_invalidate(w); + break; + case WIDX_PAY_FOR_PARK_OR_RIDES_DROPDOWN: + dropdownWidget = widget - 1; + + gDropdownItemsFormat[0] = 1142; + gDropdownItemsArgs[0] = 3279; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsArgs[1] = 3280; + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top - 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + 2, + dropdownWidget->right - dropdownWidget->left - 3 + ); + + gDropdownItemsChecked = 1 << (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY ? 0 : 1); + break; + } +} + +/** + * + * rct2: 0x00671060 + */ +static void window_editor_scenario_options_park_dropdown() +{ + rct_window *w; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (widgetIndex == WIDX_PAY_FOR_PARK_OR_RIDES_DROPDOWN && dropdownIndex != -1) { + if (dropdownIndex == 0) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY)) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_FREE_ENTRY; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) = MONEY(0, 00); + window_invalidate(w); + } + } else { + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_PARK_FREE_ENTRY; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) = MONEY(10, 00); + window_invalidate(w); + } + } + } +} + +/** + * + * rct2: 0x0067126D + */ +static void window_editor_scenario_options_park_update(rct_window *w) +{ + w->frame_no++; + window_event_invalidate_call(w); + widget_invalidate(w, WIDX_TAB_3); +} + +/** + * + * rct2: 0x00670CBA + */ +static void window_editor_scenario_options_park_invalidate() +{ + rct_window *w; + rct_widget *widgets; + int i; + uint64 pressedWidgets; + + window_get_register(w); + colour_scheme_update(w); + + widgets = window_editor_scenario_options_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_editor_scenario_options_set_pressed_tab(w); + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + for (i = WIDX_LAND_COST; i <= WIDX_ENTRY_PRICE_DECREASE; i++) + w->widgets[i].type = WWT_EMPTY; + } else { + w->widgets[WIDX_LAND_COST].type = WWT_SPINNER; + w->widgets[WIDX_LAND_COST_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_LAND_COST_DECREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_CONSTRUCTION_RIGHTS_COST].type = WWT_SPINNER; + w->widgets[WIDX_CONSTRUCTION_RIGHTS_COST_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_CONSTRUCTION_RIGHTS_COST_DECREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_PAY_FOR_PARK_OR_RIDES].type = WWT_DROPDOWN; + w->widgets[WIDX_PAY_FOR_PARK_OR_RIDES_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) { + w->widgets[WIDX_ENTRY_PRICE].type = WWT_EMPTY; + w->widgets[WIDX_ENTRY_PRICE_INCREASE].type = WWT_EMPTY; + w->widgets[WIDX_ENTRY_PRICE_DECREASE].type = WWT_EMPTY; + } else { + w->widgets[WIDX_ENTRY_PRICE].type = WWT_SPINNER; + w->widgets[WIDX_ENTRY_PRICE_INCREASE].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_ENTRY_PRICE_DECREASE].type = WWT_DROPDOWN_BUTTON; + } + } + + // Set checkboxes + pressedWidgets = w->pressed_widgets; + pressedWidgets &= ~(1 << WIDX_FORBID_TREE_REMOVAL); + pressedWidgets &= ~(1 << WIDX_FORBID_LANDSCAPE_CHANGES); + pressedWidgets &= ~(1 << WIDX_FORBID_HIGH_CONSTRUCTION); + pressedWidgets &= ~(1 << WIDX_HARD_PARK_RATING); + pressedWidgets &= ~(1 << WIDX_HARD_GUEST_GENERATION); + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_TREE_REMOVAL) + pressedWidgets |= (1 << WIDX_FORBID_TREE_REMOVAL); + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) + pressedWidgets |= (1 << WIDX_FORBID_LANDSCAPE_CHANGES); + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION) + pressedWidgets |= (1 << WIDX_FORBID_HIGH_CONSTRUCTION); + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_DIFFICULT_PARK_RATING) + pressedWidgets |= (1 << WIDX_HARD_PARK_RATING); + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_DIFFICULT_GUEST_GENERATION) + pressedWidgets |= (1 << WIDX_HARD_GUEST_GENERATION); + + w->pressed_widgets = pressedWidgets; + + w->widgets[WIDX_CLOSE].type = + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR ? WWT_EMPTY : WWT_CLOSEBOX; + + window_editor_scenario_options_anchor_border_widgets(w); +} + +/** + * + * rct2: 0x00670E5B + */ +static void window_editor_scenario_options_park_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + int x, y, arg; + rct_string_id stringId; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_editor_scenario_options_draw_tab_images(w, dpi); + + if (w->widgets[WIDX_LAND_COST].type != WWT_EMPTY) { + // Cost to buy land label + x = w->x + 8; + y = w->y + w->widgets[WIDX_LAND_COST].top; + gfx_draw_string_left(dpi, 3277, NULL, 0, x, y); + + // Cost to buy land value + x = w->x + w->widgets[WIDX_LAND_COST].left + 1; + y = w->y + w->widgets[WIDX_LAND_COST].top; + arg = RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16); + gfx_draw_string_left(dpi, 3246, &arg, 0, x, y); + } + + if (w->widgets[WIDX_CONSTRUCTION_RIGHTS_COST].type != WWT_EMPTY) { + // Cost to buy construction rights label + x = w->x + 8; + y = w->y + w->widgets[WIDX_CONSTRUCTION_RIGHTS_COST].top; + gfx_draw_string_left(dpi, 3278, NULL, 0, x, y); + + // Cost to buy construction rights value + x = w->x + w->widgets[WIDX_CONSTRUCTION_RIGHTS_COST].left + 1; + y = w->y + w->widgets[WIDX_CONSTRUCTION_RIGHTS_COST].top; + arg = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16); + gfx_draw_string_left(dpi, 3246, &arg, 0, x, y); + } + + if (w->widgets[WIDX_PAY_FOR_PARK_OR_RIDES].type != WWT_EMPTY) { + // Pay for park or rides label + x = w->x + w->widgets[WIDX_PAY_FOR_PARK_OR_RIDES].left + 1; + y = w->y + w->widgets[WIDX_PAY_FOR_PARK_OR_RIDES].top; + gfx_draw_string_left(dpi, 3279, NULL, 0, x, y); + + // Pay for park or rides value + stringId = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY ? 3279 : 3280; + gfx_draw_string_left(dpi, 1193, &stringId, 0, x, y); + } + + if (w->widgets[WIDX_ENTRY_PRICE].type != WWT_EMPTY) { + // Entry price label + x = w->x + w->widgets[WIDX_PAY_FOR_PARK_OR_RIDES].right + 8; + y = w->y + w->widgets[WIDX_ENTRY_PRICE].top; + gfx_draw_string_left(dpi, 3281, NULL, 0, x, y); + + // Entry price value + x = w->x + w->widgets[WIDX_ENTRY_PRICE].left + 1; + y = w->y + w->widgets[WIDX_ENTRY_PRICE].top; + arg = RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16); + gfx_draw_string_left(dpi, 3246, &arg, 0, x, y); + } +} + +#pragma endregion diff --git a/src/windows/editor_top_toolbar.c b/src/windows/editor_top_toolbar.c deleted file mode 100644 index ecde9f548c..0000000000 --- a/src/windows/editor_top_toolbar.c +++ /dev/null @@ -1,407 +0,0 @@ -/***************************************************************************** -* Copyright (c) 2014 Dániel Tar, 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 . -*****************************************************************************/ - -#include "../addresses.h" -#include "../localisation/string_ids.h" -#include "../sprites.h" -#include "../game.h" -#include "../editor.h" -#include "../toolbar.h" -#include "../interface/viewport.h" -#include "../interface/widget.h" -#include "../interface/window.h" -#include "dropdown.h" - -enum WINDOW_EDITOR_TOP_TOOLBAR_WIDGET_IDX { - WIDX_PAUSE, // 0, 1 - WIDX_FILE_MENU, // 1, 2 - WIDX_ZOOM_OUT, // 2, 4 - WIDX_ZOOM_IN, // 3, 8 - WIDX_ROTATE, // 4, 10 - WIDX_VIEW_MENU, // 5, 20 - WIDX_MAP, // 6, 40 - WIDX_LAND, // 7, 80 - WIDX_WATER, // 8, 100 - WIDX_SCENERY, // 9, 200 - WIDX_PATH, // 10, 400 - WIDX_CONSTRUCT_RIDE, // 11, 800 - WIDX_UNUSED1, // 12, 1000 - WIDX_UNUSED2, // 13, 2000 - WIDX_UNUSED3, // 14, 4000 - WIDX_UNUSED4, // 15, 8000 - WIDX_CLEAR_SCENERY, // 16, 10000 -}; - -typedef enum { - DDIDX_SE_LOAD_LANDSCAPE = 0, - DDIDX_SE_SAVE_LANDSCAPE = 1, - DDIDX_SE_ABOUT = 3, - DDIDX_SE_OPTIONS = 4, - DDIDX_SE_SCREENSHOT = 5, - DDIDX_SE_QUIT_GAME = 7, -} SCENARIO_EDITOR_FILE_MENU_DDIDX; - -typedef enum { - DDIDX_TD_ABOUT = 0, - DDIDX_TD_OPTIONS = 1, - DDIDX_TD_SCREENSHOT = 2, - DDIDX_TD_QUIT_GAME = 4, -} TRACK_DESINGER_FILE_MENU_DDIDX; - -static rct_widget window_editor_top_toolbar_widgets[] = { - { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, 0xFFFF }, // 1 0x009A9844 - { WWT_TRNBTN, 0, 0, 29, 0, 27, 0x20000000 | SPR_TOOLBAR_FILE, STR_DISC_AND_GAME_OPTIONS_TIP }, // 2 0x009A9854 - { WWT_TRNBTN, 1, 40, 69, 0, 27, 0x20000000 | SPR_TOOLBAR_ZOOM_OUT, STR_ZOOM_OUT_TIP }, // 4 0x009A9864 - { WWT_TRNBTN, 1, 70, 99, 0, 27, 0x20000000 | SPR_TOOLBAR_ZOOM_IN, STR_ZOOM_IN_TIP }, // 8 0x009A9874 - { WWT_TRNBTN, 1, 100, 129, 0, 27, 0x20000000 | SPR_TOOLBAR_ROTATE, STR_ROTATE_TIP }, // 10 0x009A9884 - { WWT_TRNBTN, 1, 130, 159, 0, 27, 0x20000000 | SPR_TOOLBAR_VIEW, STR_VIEW_OPTIONS_TIP }, // 20 0x009A9894 - { WWT_TRNBTN, 1, 160, 189, 0, 27, 0x20000000 | SPR_TOOLBAR_MAP, STR_SHOW_MAP_TIP }, // 40 0x009A98A4 - { WWT_TRNBTN, 2, 267, 296, 0, 27, 0x20000000 | SPR_TOOLBAR_LAND, STR_ADJUST_LAND_TIP }, // 80 0x009A98B4 - { WWT_TRNBTN, 2, 297, 326, 0, 27, 0x20000000 | SPR_TOOLBAR_WATER, STR_ADJUST_WATER_TIP }, // 100 0x009A98C4 - { WWT_TRNBTN, 2, 327, 356, 0, 27, 0x20000000 | SPR_TOOLBAR_SCENERY, STR_PLACE_SCENERY_TIP }, // 200 0x009A98D4 - { WWT_TRNBTN, 2, 357, 386, 0, 27, 0x20000000 | SPR_TOOLBAR_FOOTPATH, STR_BUILD_FOOTPATH_TIP }, // 400 0x009A98E4 - { WWT_TRNBTN, 2, 387, 416, 0, 27, 0x20000000 | SPR_TOOLBAR_CONSTRUCT_RIDE, STR_BUILD_RIDE_TIP }, // 800 0x009A98F4 - { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, 0xFFFF }, // 1000 0x009A9904 - { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, 0xFFFF }, // 2000 0x009A9914 - { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, 0xFFFF }, // 4000 0x009A9924 - { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, 0xFFFF }, // 8000 0x009A9934 - { WWT_TRNBTN, 2, 560, 589, 0, 27, 0x20000000 | SPR_TOOLBAR_CLEAR_SCENERY, STR_CLEAR_SCENERY_TIP }, // 10000 0x009A9944 - { WIDGETS_END }, -}; - -static void window_editor_top_toolbar_emptysub() { } - -static void window_editor_top_toolbar_mouseup(); -static void window_editor_top_toolbar_resize(); -static void window_editor_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_editor_top_toolbar_dropdown(); -static void window_editor_top_toolbar_invalidate(); -static void window_editor_top_toolbar_paint(); - -static void* window_editor_top_toolbar_events[] = { - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_mouseup, //(void*)0x0066f9d7, // mouseup - window_editor_top_toolbar_resize, //(void*)0x0066fada, // resize - window_editor_top_toolbar_mousedown, //(void*)0x0066fa57, // mousedown - window_editor_top_toolbar_dropdown, //(void*)0x0066fa38, // dropdown - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - (void*)0x0066fb0e, - (void*)0x0066fb5c, - (void*)0x0066fb37, - (void*)0x0066fc44, - (void*)0x0066fa74, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_emptysub, - window_editor_top_toolbar_invalidate, // (void*)0x0066f87d, // oninvalidate - window_editor_top_toolbar_paint, //(void*)0x0066f9d1, // onpaint - window_editor_top_toolbar_emptysub -}; - -/** -* Creates the main editor top toolbar window. -* rct2: 0x0066EFC8 (part of 0x0066EF38) -*/ -void window_editor_top_toolbar_open() -{ - rct_window* window; - - window = window_create(0, 0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), 28, - (uint32*)window_editor_top_toolbar_events, - WC_TOP_TOOLBAR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5); - window->widgets = window_editor_top_toolbar_widgets; - - window->enabled_widgets |= - (1 << WIDX_ZOOM_IN) | - (1 << WIDX_ZOOM_OUT) | - (1 << WIDX_ROTATE) | - (1 << WIDX_FILE_MENU) | - (1 << WIDX_LAND) | - (1 << WIDX_VIEW_MENU) | - (1 << WIDX_SCENERY) | - (1 << WIDX_WATER) | - (1 << WIDX_PATH) | - (1 << WIDX_MAP) | - (1 << WIDX_CONSTRUCT_RIDE) | - (1 << WIDX_CLEAR_SCENERY); - - window_init_scroll_widgets(window); - window->colours[0] = 7; - window->colours[1] = 12; - window->colours[2] = 24; - window->colours[3] = 1; -} - -/** -* -* rct2: 0x0066C957 -*/ -static void window_editor_top_toolbar_mouseup() -{ - short widgetIndex; - rct_window *w, *mainWindow; - - window_widget_get_registers(w, widgetIndex); - - switch (widgetIndex) { - case WIDX_ZOOM_IN: - if ((mainWindow = window_get_main()) != NULL) - window_zoom_in(mainWindow); - break; - case WIDX_ZOOM_OUT: - if ((mainWindow = window_get_main()) != NULL) - window_zoom_out(mainWindow); - break; - case WIDX_ROTATE: - if ((mainWindow = window_get_main()) != NULL) - window_rotate_camera(mainWindow); - break; - case WIDX_SCENERY: - if (!tool_set(w, WIDX_SCENERY, 0)) { - RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); - window_scenery_open(); - } - break; - case WIDX_PATH: - toggle_footpath_window(); - break; - case WIDX_LAND: - toggle_land_window(w, WIDX_LAND); - break; - case WIDX_CLEAR_SCENERY: - toggle_clear_scenery_window(w, WIDX_CLEAR_SCENERY); - break; - case WIDX_WATER: - toggle_water_window(w, WIDX_WATER); - break; - case WIDX_MAP: - window_map_open(); - break; - case WIDX_CONSTRUCT_RIDE: - window_new_ride_open(); - break; - } -} - -/** -* -* rct2: 0x0066FADA -*/ -static void window_editor_top_toolbar_resize() { - rct_window *mainWindow = window_get_main(); - rct_window *w; - - window_get_register(w); - - int eax = 0; - - if ((w->disabled_widgets & 0xFF) == 0) - eax |= (1 << 3); - - if ((w->disabled_widgets & 0xFF) == 3) - eax |= (1 << 2); - - RCT2_CALLPROC_X(0x006ECE14, 0, 0, 0, 0, (int)w, 0, 0); -} - -/** -* -* rct2: 0x0066FA57 -*/ -static void window_editor_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) -{ - if (widgetIndex == WIDX_FILE_MENU) { - short dropdownItemCount = 8; - gDropdownItemsFormat[0] = STR_LOAD_LANDSCAPE; - gDropdownItemsFormat[1] = STR_SAVE_LANDSCAPE; - gDropdownItemsFormat[2] = 0; - gDropdownItemsFormat[3] = STR_ABOUT; - gDropdownItemsFormat[4] = STR_OPTIONS; - gDropdownItemsFormat[5] = STR_SCREENSHOT; - gDropdownItemsFormat[6] = 0; - gDropdownItemsFormat[7] = STR_QUIT_SCENARIO_EDITOR; - - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { - dropdownItemCount = 5; - gDropdownItemsFormat[0] = STR_ABOUT; - gDropdownItemsFormat[1] = STR_OPTIONS; - gDropdownItemsFormat[2] = STR_SCREENSHOT; - gDropdownItemsFormat[3] = 0; - gDropdownItemsFormat[4] = STR_QUIT_TRACK_DESIGNS_MANAGER; - - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) { - gDropdownItemsFormat[4] = STR_QUIT_ROLLERCOASTER_DESIGNER; - } - } - - window_dropdown_show_text(w->x + widget->left, w->y + widget->top, - widget->bottom - widget->top + 1, w->colours[0] | 0x80, 0x80, dropdownItemCount); - } else if (widgetIndex == WIDX_VIEW_MENU) { - top_toolbar_init_view_menu(w, widget); - } -} - -/** -* -* rct2: 0x0066FA38 -*/ -void window_editor_top_toolbar_dropdown() { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - - if (widgetIndex == WIDX_FILE_MENU) { - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { - if (dropdownIndex == DDIDX_TD_ABOUT) { - window_about_open(); - } else if (dropdownIndex == DDIDX_TD_OPTIONS) { - window_options_open(); - } else if (dropdownIndex == DDIDX_TD_SCREENSHOT) { - RCT2_GLOBAL(RCT2_ADDRESS_SCREENSHOT_COUNTDOWN, sint8) = 10; - } else if (dropdownIndex == DDIDX_TD_QUIT_GAME) { - window_close_by_number(WC_47, w->number); - window_close_by_number(WC_48, w->number); - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); - } - } else { - if (dropdownIndex == DDIDX_SE_LOAD_LANDSCAPE) { - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); - } else if (dropdownIndex == DDIDX_SE_SAVE_LANDSCAPE) { - RCT2_CALLPROC(0x0066FE2A); - } else if (dropdownIndex == DDIDX_SE_ABOUT) { - window_about_open(); - } else if (dropdownIndex == DDIDX_SE_OPTIONS) { - window_options_open(); - } else if (dropdownIndex == DDIDX_SE_SCREENSHOT) { - RCT2_GLOBAL(RCT2_ADDRESS_SCREENSHOT_COUNTDOWN, sint8) = 10; - } else if (dropdownIndex == DDIDX_SE_QUIT_GAME) { - window_close_by_number(WC_47, w->number); - window_close_by_number(WC_48, w->number); - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); - } - } - } else if (widgetIndex == WIDX_VIEW_MENU) { - top_toolbar_view_menu_dropdown(dropdownIndex); - } -} - -/** -* -* rct2: 0x0066F87D -*/ -void window_editor_top_toolbar_invalidate() -{ - rct_window *w; - - window_get_register(w); - - sint16 screenWidth = max(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), 640); - - window_editor_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].left = screenWidth - 30; - window_editor_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].right = - window_editor_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].left + 29; - - window_editor_top_toolbar_widgets[WIDX_PATH].left = screenWidth - 30; - window_editor_top_toolbar_widgets[WIDX_PATH].right = - window_editor_top_toolbar_widgets[WIDX_PATH].left + 29; - - window_editor_top_toolbar_widgets[WIDX_SCENERY].left = - window_editor_top_toolbar_widgets[WIDX_PATH].left - 30; - window_editor_top_toolbar_widgets[WIDX_SCENERY].right = - window_editor_top_toolbar_widgets[WIDX_SCENERY].left + 29; - - window_editor_top_toolbar_widgets[WIDX_WATER].left = - window_editor_top_toolbar_widgets[WIDX_SCENERY].left - 30; - window_editor_top_toolbar_widgets[WIDX_WATER].right = - window_editor_top_toolbar_widgets[WIDX_WATER].left + 29; - - window_editor_top_toolbar_widgets[WIDX_LAND].left = - window_editor_top_toolbar_widgets[WIDX_WATER].left - 30; - window_editor_top_toolbar_widgets[WIDX_LAND].right = - window_editor_top_toolbar_widgets[WIDX_LAND].left + 29; - - window_editor_top_toolbar_widgets[WIDX_CLEAR_SCENERY].left = - window_editor_top_toolbar_widgets[WIDX_LAND].left - 30; - window_editor_top_toolbar_widgets[WIDX_CLEAR_SCENERY].right = - window_editor_top_toolbar_widgets[WIDX_CLEAR_SCENERY].left + 29; - - window_editor_top_toolbar_widgets[WIDX_ZOOM_OUT].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_ZOOM_IN].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_ROTATE].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_VIEW_MENU].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_MAP].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_CLEAR_SCENERY].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_LAND].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_WATER].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_SCENERY].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_PATH].type = WWT_EMPTY; - window_editor_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].type = WWT_EMPTY; - - - if (g_editor_step == EDITOR_STEP_LANDSCAPE_EDITOR) { - window_editor_top_toolbar_widgets[WIDX_ZOOM_OUT].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_ZOOM_IN].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_ROTATE].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_VIEW_MENU].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_MAP].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_CLEAR_SCENERY].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_LAND].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_WATER].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_SCENERY].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_PATH].type = WWT_TRNBTN; - } else if (g_editor_step == EDITOR_STEP_ROLLERCOASTER_DESIGNER) { - window_editor_top_toolbar_widgets[WIDX_ZOOM_OUT].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_ZOOM_IN].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_ROTATE].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_VIEW_MENU].type = WWT_TRNBTN; - window_editor_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].type = WWT_TRNBTN; - } - - if (window_find_by_class(0x94) == NULL) - w->pressed_widgets &= ~(1 << WIDX_PATH); - else - w->pressed_widgets |= (1 << WIDX_PATH); -} - -/** -* -* rct2: 0x0066F9D1 -*/ -static void window_editor_top_toolbar_paint() -{ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - - window_draw_widgets(w, dpi); -} \ No newline at end of file diff --git a/src/windows/finances.c b/src/windows/finances.c index 58b7f0fa09..17fc47d1e9 100644 --- a/src/windows/finances.c +++ b/src/windows/finances.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../interface/graph.h" #include "../interface/widget.h" @@ -32,6 +33,7 @@ #include "../scenario.h" #include "../sprites.h" #include "dropdown.h" +#include "../interface/themes.h" enum { WINDOW_FINANCES_PAGE_SUMMARY, @@ -436,6 +438,8 @@ static void* window_finances_page_events[] = { window_finances_research_events }; +static void window_finances_set_colours(); + #pragma endregion #pragma region Enabled widgets @@ -508,6 +512,17 @@ static uint32 window_finances_page_enabled_widgets[] = { (1 << WIDX_SCENERY_AND_THEMING) }; +static uint32 window_finances_page_hold_down_widgets[] = { + (1 << WIDX_LOAN_INCREASE) | + (1 << WIDX_LOAN_DECREASE), + + 0, + 0, + 0, + 0, + 0 +}; + #pragma endregion const int window_finances_tab_animation_loops[] = { 16, 32, 32, 32, 38, 16 }; @@ -527,28 +542,22 @@ void window_finances_open() w = window_bring_to_front_by_class(WC_FINANCES); if (w == NULL) { w = window_create_auto_pos(530, 257, window_finances_page_events[0], WC_FINANCES, WF_10); - w->widgets = window_finances_page_widgets[0]; - w->enabled_widgets = 0x1BF4; w->number = 0; - w->page = 0; w->frame_no = 0; - w->disabled_widgets = 0; - w->colours[0] = 1; - w->colours[1] = 19; - w->colours[2] = 19; + research_update_uncompleted_types(); } - w->page = 0; + w->page = WINDOW_FINANCES_PAGE_SUMMARY; window_invalidate(w); w->width = 530; w->height = 257; window_invalidate(w); - w->widgets = window_finances_page_widgets[0]; - w->enabled_widgets = window_finances_page_enabled_widgets[0]; - w->var_020 = RCT2_GLOBAL(0x00988E3C, uint32); - w->event_handlers = window_finances_page_events[0]; + w->widgets = window_finances_page_widgets[WINDOW_FINANCES_PAGE_SUMMARY]; + w->enabled_widgets = window_finances_page_enabled_widgets[WINDOW_FINANCES_PAGE_SUMMARY]; + w->hold_down_widgets = window_finances_page_hold_down_widgets[WINDOW_FINANCES_PAGE_SUMMARY]; + w->event_handlers = window_finances_page_events[WINDOW_FINANCES_PAGE_SUMMARY]; w->pressed_widgets = 0; w->disabled_widgets = 0; window_init_scroll_widgets(w); @@ -599,13 +608,13 @@ static void window_finances_summary_mousedown(int widgetIndex, rct_window*w, rct case WIDX_LOAN_INCREASE: newLoan = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) + MONEY(1000, 00); RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_BORROW_ANY_MORE_MONEY; - game_do_command(0, 1, 0, newLoan, GAME_COMMAND_SET_CURRENT_LOAN, 0, 0); + finance_set_loan(newLoan); break; case WIDX_LOAN_DECREASE: if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) > 0) { newLoan = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) - MONEY(1000, 00); RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_PAY_BACK_LOAN; - game_do_command(0, 1, 0, newLoan, GAME_COMMAND_SET_CURRENT_LOAN, 0, 0); + finance_set_loan(newLoan); } break; } @@ -632,6 +641,7 @@ static void window_finances_summary_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_SUMMARY]) { w->widgets = window_finances_page_widgets[WINDOW_FINANCES_PAGE_SUMMARY]; @@ -805,6 +815,7 @@ static void window_finances_financial_graph_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH]) { w->widgets = window_finances_page_widgets[WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH]; @@ -858,7 +869,7 @@ static void window_finances_financial_graph_paint() money32 *balanceHistory = RCT2_ADDRESS(RCT2_ADDRESS_BALANCE_HISTORY, money32); for (i = 0; i < 64; i++) { money32 balance = balanceHistory[i]; - if (balance == 0x80000000) + if (balance == MONEY32_UNDEFINED) continue; // Modifier balance then keep halfing until less than 127 pixels @@ -927,6 +938,7 @@ static void window_finances_park_value_graph_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_VALUE_GRAPH]) { w->widgets = window_finances_page_widgets[WINDOW_FINANCES_PAGE_VALUE_GRAPH]; @@ -976,7 +988,7 @@ static void window_finances_park_value_graph_paint() money32 *parkValueHistory = RCT2_ADDRESS(RCT2_ADDRESS_PARK_VALUE_HISTORY, money32); for (i = 0; i < 64; i++) { money32 balance = parkValueHistory[i]; - if (balance == 0x80000000) + if (balance == MONEY32_UNDEFINED) continue; // Modifier balance then keep halfing until less than 255 pixels @@ -1045,6 +1057,7 @@ static void window_finances_profit_graph_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_PROFIT_GRAPH]) { w->widgets = window_finances_page_widgets[WINDOW_FINANCES_PAGE_PROFIT_GRAPH]; @@ -1094,7 +1107,7 @@ static void window_finances_profit_graph_paint() money32 *weeklyProfitHistory = RCT2_ADDRESS(RCT2_ADDRESS_WEEKLY_PROFIT_HISTORY, money32); for (i = 0; i < 64; i++) { money32 balance = weeklyProfitHistory[i]; - if (balance == 0x80000000) + if (balance == MONEY32_UNDEFINED) continue; // Modifier balance then keep halfing until less than 127 pixels @@ -1167,6 +1180,7 @@ static void window_finances_marketing_invalidate() int i; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_MARKETING]) { w->widgets = window_finances_page_widgets[WINDOW_FINANCES_PAGE_MARKETING]; @@ -1177,9 +1191,8 @@ static void window_finances_marketing_invalidate() // Count number of active campaigns int numActiveCampaigns = 0; - uint8 *campaignDaysLeft = RCT2_ADDRESS(0x01358102, uint8); for (i = 0; i < ADVERTISING_CAMPAIGN_COUNT; i++) - if (campaignDaysLeft[i] != 0) + if (gMarketingCampaignDaysLeft[i] != 0) numActiveCampaigns++; int y = max(1, numActiveCampaigns) * 10 + 92; @@ -1204,7 +1217,7 @@ static void window_finances_marketing_invalidate() continue; } - if (campaignDaysLeft[i] != 0) + if (gMarketingCampaignDaysLeft[i] != 0) continue; campaginButton->type = WWT_DROPDOWN_BUTTON; @@ -1235,27 +1248,24 @@ static void window_finances_marketing_paint() y = w->y + 62; int noCampaignsActive = 1; - uint8 *campaignDaysLeft = RCT2_ADDRESS(0x01358102, uint8); - uint8 *campaignRideIndex = RCT2_ADDRESS(0x01358116, uint8); - for (i = 0; i < ADVERTISING_CAMPAIGN_COUNT; i++) { - if (campaignDaysLeft[i] == 0) + if (gMarketingCampaignDaysLeft[i] == 0) continue; noCampaignsActive = 0; - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); // Set special parameters switch (i) { case ADVERTISING_CAMPAIGN_RIDE_FREE: case ADVERTISING_CAMPAIGN_RIDE: - ride = GET_RIDE(campaignRideIndex[i]); + ride = GET_RIDE(gMarketingCampaignRideIndex[i]); RCT2_GLOBAL(0x013CE952, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; break; case ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE: - shopString = campaignRideIndex[i] + 2016; // STR_BALLOONS+ + shopString = gMarketingCampaignRideIndex[i] + 2016; // STR_BALLOONS+ if (shopString >= 2048) // STR_AN_UMBRELLA shopString += 96; // STR_ON_RIDE_PHOTOS+ RCT2_GLOBAL(0x013CE952, uint16) = shopString; @@ -1266,7 +1276,7 @@ static void window_finances_marketing_paint() gfx_draw_string_left_clipped(dpi, STR_VOUCHERS_FOR_FREE_ENTRY_TO + i, (void*)0x013CE952, 0, x + 4, y, 296); // Duration - weeksRemainingStringId = (STR_MARKETING_1_WEEK - 1) + (campaignDaysLeft[i] % 128); + weeksRemainingStringId = (STR_MARKETING_1_WEEK - 1) + (gMarketingCampaignDaysLeft[i] % 128); gfx_draw_string_left(dpi, STR_MARKETING_WEEKS_REMAINING, &weeksRemainingStringId, 0, x + 304, y); y += 10; @@ -1294,7 +1304,7 @@ static void window_finances_marketing_paint() continue; } - if (campaignDaysLeft[i] != 0) + if (gMarketingCampaignDaysLeft[i] != 0) continue; money32 pricePerWeek = AdvertisingCampaignPricePerWeek[i]; @@ -1344,7 +1354,7 @@ static void window_finances_research_mouseup() case WIDX_SCENERY_AND_THEMING: activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); activeResearchTypes ^= 1 << (widgetIndex - WIDX_TRANSPORT_RIDES); - game_do_command(0, (1 << 8) | 1, 0, activeResearchTypes, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0); + research_set_priority(activeResearchTypes); break; } } @@ -1372,7 +1382,7 @@ static void window_finances_research_mousedown(int widgetIndex, rct_window *w, r w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, 4, dropdownWidget->right - dropdownWidget->left - 3 ); @@ -1396,7 +1406,7 @@ static void window_finances_research_dropdown() if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON || dropdownIndex == -1) return; - game_do_command(0, 1, 0, dropdownIndex, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0); + research_set_funding(dropdownIndex); } /** @@ -1420,6 +1430,7 @@ static void window_finances_research_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_RESEARCH]) { w->widgets = window_finances_page_widgets[WINDOW_FINANCES_PAGE_RESEARCH]; @@ -1427,7 +1438,10 @@ static void window_finances_research_invalidate() } window_finances_set_pressed_tab(w); - + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) == RESEARCH_STAGE_FINISHED_ALL) { + window_finances_research_widgets[WIDX_RESEARCH_FUNDING].type = WWT_EMPTY; + window_finances_research_widgets[WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON].type = WWT_EMPTY; + } int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); // Current funding @@ -1493,7 +1507,7 @@ static void window_finances_set_page(rct_window *w, int page) } w->enabled_widgets = window_finances_page_enabled_widgets[page]; - w->var_020 = RCT2_ADDRESS(0x00988E3C, uint32)[page]; + w->hold_down_widgets = window_finances_page_hold_down_widgets[page]; w->event_handlers = window_finances_page_events[page]; w->widgets = window_finances_page_widgets[page]; w->disabled_widgets = 0; @@ -1507,8 +1521,8 @@ static void window_finances_set_page(rct_window *w, int page) w->width = 530; w->height = 257; } - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); + window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); @@ -1548,4 +1562,4 @@ static void window_finances_draw_tab_images(rct_drawpixelinfo *dpi, rct_window * window_finances_draw_tab_image(dpi, w, WINDOW_FINANCES_PAGE_RESEARCH, SPR_TAB_FINANCES_RESEARCH_0); } -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/windows/footpath.c b/src/windows/footpath.c index 0c483e4df9..c3135efe4a 100644 --- a/src/windows/footpath.c +++ b/src/windows/footpath.c @@ -30,11 +30,13 @@ #include "../world/footpath.h" #include "../world/map.h" #include "dropdown.h" +#include "../interface/themes.h" +#include "../cheats.h" enum { PATH_CONSTRUCTION_MODE_LAND, - PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL, - PATH_CONSTRUCTION_MODE_2 + PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL, + PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL }; enum { @@ -104,7 +106,7 @@ static rct_widget window_footpath_widgets[] = { static void window_footpath_emptysub() { } static void window_footpath_close(); static void window_footpath_mouseup(); -static void window_footpath_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_footpath_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); static void window_footpath_dropdown(); static void window_footpath_update(rct_window *w); static void window_footpath_toolupdate(); @@ -146,13 +148,19 @@ static void* window_footpath_events[] = { }; money32 _window_footpath_cost; +sint8 _window_footpath_provisional_path_arrow_timer; +static void window_footpath_mousedown_direction(int direction); +static void window_footpath_mousedown_slope(int slope); static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget *widget, int showQueues); static void window_footpath_set_provisional_path_at_point(int x, int y); -static int window_footpath_set_provisional_path(int type, int x, int y, int z, int slope); +static void window_footpath_set_selection_start_bridge_at_point(int screenX, int screenY); static void window_footpath_place_path_at_point(int x, int y); +static void window_footpath_start_bridge_at_point(int screenX, int screenY); static void window_footpath_construct(); static void window_footpath_remove(); +static void window_footpath_set_enabled_and_pressed_widgets(); +static void footpath_get_next_path_info(int *type, int *x, int *y, int *z, int *slope); /** * @@ -161,6 +169,8 @@ static void window_footpath_remove(); void window_footpath_open() { rct_window* window; + sint16 pathId; + rct_path_type *pathType; // Check if window is already open window = window_bring_to_front_by_class(WC_FOOTPATH); @@ -196,16 +206,20 @@ void window_footpath_open() window_init_scroll_widgets(window); window_push_others_right(window); show_gridlines(); - window->colours[0] = 24; - window->colours[1] = 24; - window->colours[2] = 24; + + // If a restricted path was selected when the game is no longer in Sandbox mode, reset it + pathId = RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16); + pathType = g_pathTypeEntries[pathId]; + if((pathType->flags & 4) && !gSandboxMode) { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = 0; + } tool_cancel(); RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_LAND; tool_set(window, WIDX_CONSTRUCT_ON_LAND, 17); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; - RCT2_CALLPROC_EBPSAFE(0x006A855C); + window_footpath_set_enabled_and_pressed_widgets(); } /** @@ -218,9 +232,9 @@ static void window_footpath_close() window_get_register(w); - sub_6A7831(); + footpath_provisional_update(); viewport_set_visibility(0); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2; window_invalidate_by_class(WC_TOP_TOOLBAR); hide_gridlines(); @@ -251,31 +265,31 @@ static void window_footpath_mouseup() if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_LAND) break; - _window_footpath_cost = 0x80000000; + _window_footpath_cost = MONEY32_UNDEFINED; tool_cancel(); - sub_6A7831(); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + footpath_provisional_update(); + map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2; RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_LAND; tool_set(w, WIDX_CONSTRUCT_ON_LAND, 17); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; - RCT2_CALLPROC_EBPSAFE(0x006A855C); + window_footpath_set_enabled_and_pressed_widgets(); break; case WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL: - if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) + if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL) break; - _window_footpath_cost = 0x80000000; + _window_footpath_cost = MONEY32_UNDEFINED; tool_cancel(); - sub_6A7831(); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + footpath_provisional_update(); + map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2; - RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL; + RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL; tool_set(w, WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL, 12); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; - RCT2_CALLPROC_EBPSAFE(0x006A855C); + window_footpath_set_enabled_and_pressed_widgets(); break; } } @@ -294,25 +308,25 @@ static void window_footpath_mousedown(int widgetIndex, rct_window*w, rct_widget* window_footpath_show_footpath_types_dialog(w, widget, 1); break; case WIDX_DIRECTION_NW: - RCT2_CALLPROC_X(0x006A8111, 0, 0, 0, 0, (int)w, 0, 0); + window_footpath_mousedown_direction(0); break; case WIDX_DIRECTION_NE: - RCT2_CALLPROC_X(0x006A8135, 0, 0, 0, 0, (int)w, 0, 0); + window_footpath_mousedown_direction(1); break; case WIDX_DIRECTION_SW: - RCT2_CALLPROC_X(0x006A815C, 0, 0, 0, 0, (int)w, 0, 0); + window_footpath_mousedown_direction(2); break; case WIDX_DIRECTION_SE: - RCT2_CALLPROC_X(0x006A8183, 0, 0, 0, 0, (int)w, 0, 0); + window_footpath_mousedown_direction(3); break; case WIDX_SLOPEDOWN: - RCT2_CALLPROC_X(0x006A81AA, 0, 0, 0, 0, (int)w, 0, 0); + window_footpath_mousedown_slope(6); break; case WIDX_LEVEL: - RCT2_CALLPROC_X(0x006A81C5, 0, 0, 0, 0, (int)w, 0, 0); + window_footpath_mousedown_slope(0); break; case WIDX_SLOPEUP: - RCT2_CALLPROC_X(0x006A81E0, 0, 0, 0, 0, (int)w, 0, 0); + window_footpath_mousedown_slope(2); break; } } @@ -344,16 +358,19 @@ static void window_footpath_dropdown() pathId = RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16); } else { int flags = 4; - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gSandboxMode) flags = 0; j = 0; for (i = 0; i < 16; i++) { - pathType = RCT2_ADDRESS(RCT2_ADDRESS_PATH_TYPES, rct_path_type*)[i]; + pathType = g_pathTypeEntries[i]; if (pathType == (rct_path_type*)-1) continue; if (pathType->flags & flags) continue; + // Skip queue lines of scenario editor-only paths (only applicable when the game is in sandbox mode) + if(widgetIndex == WIDX_QUEUELINE_TYPE && (pathType->flags & 4)) + continue; if (j == pathId) break; @@ -364,8 +381,8 @@ static void window_footpath_dropdown() // Set selected path id RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = pathId; - sub_6A7831(); - _window_footpath_cost = 0x80000000; + footpath_provisional_update(); + _window_footpath_cost = MONEY32_UNDEFINED; window_invalidate(w); } @@ -384,7 +401,7 @@ static void window_footpath_toolupdate() if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { window_footpath_set_provisional_path_at_point(x, y); } else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) { - RCT2_CALLPROC_X(0x006A8388, x, y, 0, 0, (int)w, 0, 0); + window_footpath_set_selection_start_bridge_at_point(x, y); } } @@ -400,11 +417,10 @@ static void window_footpath_tooldown() window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { + if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) window_footpath_place_path_at_point(x, y); - } else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) { - RCT2_CALLPROC_X(0x006A840F, x, y, 0, 0, (int)w, 0, 0); - } + else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) + window_footpath_start_bridge_at_point(x, y); } /** @@ -420,7 +436,7 @@ static void window_footpath_tooldrag() window_tool_get_registers(w, widgetIndex, x, y); if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { - RCT2_CALLPROC_X(0x006A82C5, x, y, 0, 0, (int)w, 0, 0); + window_footpath_place_path_at_point(x, y); } } @@ -437,7 +453,43 @@ static void window_footpath_toolup() window_tool_get_registers(w, widgetIndex, x, y); if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { - RCT2_CALLPROC_X(0x006A8380, x, y, 0, 0, (int)w, 0, 0); + // The function at 0x006A8380 in rct2 is just the following: + RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; + } +} + +/** + * + * rct2: 0x006A7760 + */ +static void window_footpath_update_provisional_path_for_bridge_mode(rct_window *w) +{ + int type, x, y, z, slope; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) != PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) + return; + + // Update provisional bridge mode path + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & (1 << 1))) { + footpath_get_next_path_info(&type, &x, &y, &z, &slope); + _window_footpath_cost = footpath_provisional_set(type, x, y, z, slope); + widget_invalidate(w, WIDX_CONSTRUCT); + } + + // Update little directional arrow on provisional bridge mode path + if (--_window_footpath_provisional_path_arrow_timer < 0) { + _window_footpath_provisional_path_arrow_timer = 5; + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) ^= PROVISIONAL_PATH_FLAG_SHOW_ARROW; + footpath_get_next_path_info(&type, &x, &y, &z, &slope); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Z, uint16) = z * 8; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8); + if (RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & PROVISIONAL_PATH_FLAG_SHOW_ARROW) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 2); + else + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 2); + map_invalidate_tile_full(x, y); } } @@ -447,10 +499,8 @@ static void window_footpath_toolup() */ static void window_footpath_update(rct_window *w) { - // Invalidate construct button widget_invalidate(w, WIDX_CONSTRUCT); - - RCT2_CALLPROC_EBPSAFE(0x006A7760); + window_footpath_update_provisional_path_for_bridge_mode(w); // Check tool if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_LAND) { @@ -460,7 +510,7 @@ static void window_footpath_update(rct_window *w) window_close(w); else if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) != WIDX_CONSTRUCT_ON_LAND) window_close(w); - } else if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { + } else if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL) { if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) window_close(w); else if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_FOOTPATH) @@ -481,6 +531,7 @@ static void window_footpath_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); // Press / unpress footpath and queue type buttons w->pressed_widgets &= ~(1 << WIDX_FOOTPATH_TYPE); @@ -490,19 +541,27 @@ static void window_footpath_invalidate() (1 << WIDX_QUEUELINE_TYPE); // Enable / disable construct button - window_footpath_widgets[WIDX_CONSTRUCT].type = RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_LAND ? WWT_EMPTY : WWT_IMGBTN; + window_footpath_widgets[WIDX_CONSTRUCT].type = + RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL ? + WWT_IMGBTN : WWT_EMPTY; // Set footpath and queue type button images selectedPath = RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, uint16); - pathType = RCT2_ADDRESS(RCT2_ADDRESS_PATH_TYPES, rct_path_type*)[selectedPath]; + pathType = g_pathTypeEntries[selectedPath]; int pathImage = 71 + pathType->image; window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage; - window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = pathImage + 1; - window_footpath_widgets[WIDX_QUEUELINE_TYPE].type = WWT_FLATBTN; - // Disable queue in if in editor - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + // Disable queue line button when the path is scenario editor-only (and therefore usually shouldn't have one) + if(!(pathType->flags & 4)) { + window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = pathImage + 1; + window_footpath_widgets[WIDX_QUEUELINE_TYPE].type = WWT_FLATBTN; + } else { + window_footpath_widgets[WIDX_QUEUELINE_TYPE].type = WWT_EMPTY; + } + + // Disable queue line button if in Scenario Editor + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) window_footpath_widgets[WIDX_QUEUELINE_TYPE].type = WWT_EMPTY; } @@ -524,14 +583,14 @@ static void window_footpath_paint() if (!(w->disabled_widgets & (1 << WIDX_CONSTRUCT))) { // Get construction image image = (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) % 4; - if (RCT2_GLOBAL(0x00F3EF91, uint8) == 2) + if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 2) image += 4; - else if (RCT2_GLOBAL(0x00F3EF91, uint8) == 6) + else if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 6) image += 8; image = RCT2_ADDRESS(0x0098D7E0, uint8)[image]; selectedPath = RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, uint16); - pathType = RCT2_ADDRESS(RCT2_ADDRESS_PATH_TYPES, rct_path_type*)[selectedPath]; + pathType = g_pathTypeEntries[selectedPath]; image += pathType->image; if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) != SELECTED_PATH_TYPE_NORMAL) image += 51; @@ -550,7 +609,7 @@ static void window_footpath_paint() // Draw cost x = w->x + (window_footpath_widgets[WIDX_CONSTRUCT].left + window_footpath_widgets[WIDX_CONSTRUCT].right) / 2; y = w->y + window_footpath_widgets[WIDX_CONSTRUCT].bottom - 12; - if (_window_footpath_cost != 0x80000000) + if (_window_footpath_cost != MONEY32_UNDEFINED) if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) gfx_draw_string_centred(dpi, STR_COST_LABEL, x, y, 0, &_window_footpath_cost); } @@ -566,11 +625,12 @@ static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget numPathTypes = 0; flags = 4; - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + // If the game is in sandbox mode, also show paths that are normally restricted to the scenario editor, but not their queues (since these usually shouldn't have one) + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || (gSandboxMode && !showQueues)) flags = 0; for (i = 0; i < 16; i++) { - pathType = RCT2_ADDRESS(RCT2_ADDRESS_PATH_TYPES, rct_path_type*)[i]; + pathType = g_pathTypeEntries[i]; if (pathType == (rct_path_type*)-1) continue; if (pathType->flags & flags) @@ -596,75 +656,116 @@ static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget ); } +/** + * + * rct2: 0x006A8111 0x006A8135 0x006A815C 0x006A8183 + */ +static void window_footpath_mousedown_direction(int direction) +{ + footpath_provisional_update(); + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) = (direction - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) & 3; + _window_footpath_cost = MONEY32_UNDEFINED; + window_footpath_set_enabled_and_pressed_widgets(); +} + +/** +* +* rct2: 0x006A81AA 0x006A81C5 0x006A81E0 +*/ +static void window_footpath_mousedown_slope(int slope) +{ + footpath_provisional_update(); + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) = slope; + _window_footpath_cost = MONEY32_UNDEFINED; + window_footpath_set_enabled_and_pressed_widgets(); +} + /** * * rct2: 0x006A81FB */ static void window_footpath_set_provisional_path_at_point(int x, int y) { - int z, slope, pathType; + int slope, pathType, interactionType; rct_map_element *mapElement; - RCT2_CALLPROC_EBPSAFE(0x0068AAE1); - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~4; + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 2); - get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); + rct_xy16 mapCoord = { 0 }; + get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_FOOTPATH & VIEWPORT_INTERACTION_MASK_TERRAIN, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, NULL); + x = mapCoord.x; + y = mapCoord.y; - if (z == 0) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~1; - sub_6A7831(); + if (interactionType == VIEWPORT_INTERACTION_ITEM_NONE) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + footpath_provisional_update(); } else { // Check for change - if ((RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & 2) && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16) == x && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16) == y && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint8) == mapElement->base_height) + if ((RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & (1 << 1)) && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16) == x && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16) == y && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint8) == mapElement->base_height) return; // Set map selection - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = y; - sub_6A7831(); + footpath_provisional_update(); // Set provisional path slope = RCT2_ADDRESS(0x0098D8B4, uint8)[mapElement->properties.surface.slope & 0x1F]; - if (z == 6) + if (interactionType == VIEWPORT_INTERACTION_ITEM_FOOTPATH) slope = mapElement->properties.surface.slope & 7; pathType = (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) << 7) + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, uint8); - _window_footpath_cost = window_footpath_set_provisional_path(pathType, x, y, mapElement->base_height, slope); - // window_invalidate_by_id(eax, ebx); + _window_footpath_cost = footpath_provisional_set(pathType, x, y, mapElement->base_height, slope); + window_invalidate_by_class(WC_FOOTPATH); } } /** - * - * rct2: 0x006A76FF - */ -static int window_footpath_set_provisional_path(int type, int x, int y, int z, int slope) +* +* rct2: 0x006A8388 +*/ +static void window_footpath_set_selection_start_bridge_at_point(int screenX, int screenY) { - int eax, cost; + int x, y, direction; + rct_map_element *mapElement; - RCT2_CALLPROC_EBPSAFE(0x006A77FF); + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0) & ~(1 << 2); - // Try and show provisional path - cost = game_do_command(x, (slope << 8) | 121, y, (type << 8) | z, GAME_COMMAND_PLACE_PATH, 0, 0); + footpath_bridge_get_info_from_pos(screenX, screenY, &x, &y, &direction, &mapElement); + if (x == (sint16)0x8000) + return; - if (cost != MONEY32_UNDEFINED) { - RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint8) = z & 0xFF; - RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) |= 2; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0) | (1 << 2); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = y; - eax = 3; - if (RCT2_GLOBAL(0x00F3EFA4, uint8) & 2) - eax = 1; - viewport_set_visibility((uint8)eax); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = direction; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Y, uint16) = y; + + int z = mapElement->base_height; + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SURFACE) { + uint8 slope = mapElement->properties.surface.slope; + if (slope & 0xf) + z += 2; // Add 2 for a slope + if (slope & 0x10) + z += 2; // Add another 2 for a steep slope } - return cost; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Z, uint16) = z << 3; + + map_invalidate_selection_rect(); } /** @@ -673,30 +774,32 @@ static int window_footpath_set_provisional_path(int type, int x, int y, int z, i */ static void window_footpath_place_path_at_point(int x, int y) { - int z, presentType, selectedType, cost; + int interactionType, presentType, selectedType, z, cost; rct_map_element *mapElement; if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) != 0) return; - sub_6A7831(); + footpath_provisional_update(); - get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); - if (z == 0) + rct_xy16 mapCoord = { 0 }; + get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_FOOTPATH & VIEWPORT_INTERACTION_MASK_TERRAIN, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, NULL); + x = mapCoord.x; + y = mapCoord.y; + + if (interactionType == VIEWPORT_INTERACTION_ITEM_NONE) return; // Set path presentType = RCT2_ADDRESS(0x0098D8B4, uint8)[mapElement->properties.path.type & 0x1F]; - if (z == 6) + if (interactionType == VIEWPORT_INTERACTION_ITEM_FOOTPATH) presentType = mapElement->properties.path.type & 7; z = mapElement->base_height; selectedType = (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) << 7) + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, uint8); - // Prepare error text - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_BUILD_FOOTPATH_HERE; - // Try and place path - cost = game_do_command(x, (presentType << 8) | 1, y, (selectedType << 8) | z, GAME_COMMAND_PLACE_PATH, 0, 0); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_BUILD_FOOTPATH_HERE; + cost = footpath_place(selectedType, x, y, z, presentType, GAME_COMMAND_FLAG_APPLY); if (cost == MONEY32_UNDEFINED) { RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 1; @@ -710,79 +813,146 @@ static void window_footpath_place_path_at_point(int x, int y) /** * + * rct2: 0x006A840F + */ +static void window_footpath_start_bridge_at_point(int screenX, int screenY) +{ + int x, y, z, direction; + rct_map_element *mapElement; + + footpath_bridge_get_info_from_pos(screenX, screenY, &x, &y, &direction, &mapElement); + if (x == (sint16)0x8000) + return; + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SURFACE) { + // If we start the path on a slope, the arrow is slightly raised, so we + // expect the path to be slightly raised as well. + uint8_t slope = mapElement->properties.surface.slope; + z = mapElement->base_height; + if (slope & 0x10) { + // Steep diagonal slope + z += 4; + } else if (slope & 0x0f) { + // Normal slope + z += 2; + } + } else { + z = mapElement->base_height; + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { + if (mapElement->properties.path.type & 4) { + if (direction == (mapElement->properties.path.type & 3)) + z += 2; + } + } + } + + tool_cancel(); + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) = z * 8; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) = direction; + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) = 0; + _window_footpath_provisional_path_arrow_timer = 0; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS, uint8) = 255; + window_footpath_set_enabled_and_pressed_widgets(); +} + +/** + * Construct a piece of footpath while in bridge building mode. * rct2: 0x006A79B7 */ static void window_footpath_construct() { - RCT2_CALLPROC_EBPSAFE(0x006A79B7); + _window_footpath_cost = MONEY32_UNDEFINED; + footpath_provisional_update(); + + int type, x, y, z, slope; + footpath_get_next_path_info(&type, &x, &y, &z, &slope); + + // Try to place the path at the desired location + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 0x498; + money32 cost = footpath_place(type, x, y, z, slope, 0); + + if (cost != MONEY32_UNDEFINED) { + // It is possible, let's remove walls between the old and new piece of path + uint8 direction = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8); + map_remove_intersecting_walls(x, y, z, z + 4 + (slope & 0xf ? 2 : 0), direction ^ 2); + map_remove_intersecting_walls( + x - TileDirectionDelta[direction].x, + y - TileDirectionDelta[direction].y, + z, z + 4, direction + ); + } + + // Actually place the path now + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 0x498; + cost = footpath_place(type, x, y, z, slope, GAME_COMMAND_FLAG_APPLY); + + if (cost != MONEY32_UNDEFINED) { + sound_play_panned( + SOUND_PLACE_ITEM, + 0x8001, + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) + ); + + if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS, uint8) = 0xff; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8); + } + + if (RCT2_GLOBAL(0x00F3EFA4, uint8) & 2) + viewport_set_visibility(1); + + // If we have just built an upwards slope, the next path to construct is + // a bit higher. Note that the z returned by footpath_get_next_path_info + // already is lowered if we are building a downwards slope. + if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 2) + z += 2; + + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) = z << 3; + } + + window_footpath_set_enabled_and_pressed_widgets(); } /** * - * rct2: 0x006A7863 + * rct2: 0x006A78EF */ -static void window_footpath_remove() +static void footpath_remove_map_element(rct_map_element *mapElement) { - int x, y, lastTile; - rct_map_element *mapElement; + int x, y, z; - // RCT2_CALLPROC_EBPSAFE(0x006A7863); - - _window_footpath_cost = MONEY32_UNDEFINED; - sub_6A7831(); - - x = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) / 32; - y = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) / 32; - int dl = (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) >> 3) & 0xFF; - int dh = dl - 2; - - if (x >= 256 || y >= 256) - goto loc_6A79B0; - - mapElement = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[y * 256 + x]; - do { - if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH) { - if (mapElement->base_height == dl) { - if (mapElement->properties.path.type & 4) - if (((mapElement->properties.path.type & 3) ^ 2) != RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8)) - continue; - goto loc_6A78EF; - } else if (mapElement->base_height == dh) { - if (!(mapElement->properties.path.type & 4)) - if ((mapElement->properties.path.type & 3) == RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8)) - continue; - goto loc_6A78EF; - } - } - lastTile = (mapElement->flags & MAP_ELEMENT_FLAG_LAST_TILE) != 0; - mapElement++; - } while (!lastTile); - goto loc_6A79B0; - -loc_6A78EF: - dl = mapElement->base_height; + z = mapElement->base_height; int pathType = mapElement->properties.path.type; if (pathType & 4) { pathType &= 3; pathType ^= 2; if (pathType == RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8)) - dl += 2; + z += 2; } - + // Find a connected edge int edge = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) ^ 2; if (!(mapElement->properties.path.edges & (1 << edge))) { - edge = (edge + 1) % 4; + edge = (edge + 1) & 3; if (!(mapElement->properties.path.edges & (1 << edge))) { - edge = (edge + 2) % 4; + edge = (edge + 2) & 3; if (!(mapElement->properties.path.edges & (1 << edge))) { - edge = (edge - 1) % 4; + edge = (edge - 1) & 3; if (!(mapElement->properties.path.edges & (1 << edge))) edge ^= 2; } } } - + // Remove path RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_REMOVE_FOOTPATH_FROM_HERE; footpath_remove( @@ -794,15 +964,166 @@ loc_6A78EF: // Move selection edge ^= 2; - x = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) - RCT2_GLOBAL(0x00993CCC + (edge * 4), sint16); - y = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) - RCT2_GLOBAL(0x00993CCE + (edge * 4), sint16); + x = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) - TileDirectionDelta[edge].x; + y = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) - TileDirectionDelta[edge].y; RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) = dl << 3; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) = z << 3; RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) = edge; - RCT2_GLOBAL(0x00F3EF9E, uint8) = 255; - -loc_6A79B0: - RCT2_CALLPROC_EBPSAFE(0x006A855C); + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS, uint8) = 255; } +/** + * + * rct2: 0x006A7873 + */ +static rct_map_element *footpath_get_map_element_to_remove() +{ + rct_map_element *mapElement; + int x, y, z, zLow; + + x = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) / 32; + y = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) / 32; + if (x >= 256 || y >= 256) + return NULL; + + z = (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) >> 3) & 0xFF; + zLow = z - 2; + + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { + if (mapElement->base_height == z) { + if (mapElement->properties.path.type & 4) + if (((mapElement->properties.path.type & 3) ^ 2) != RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8)) + continue; + + return mapElement; + } else if (mapElement->base_height == zLow) { + if (!(mapElement->properties.path.type & 4)) + if ((mapElement->properties.path.type & 3) == RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8)) + continue; + + return mapElement; + } + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + +/** + * + * rct2: 0x006A7863 + */ +static void window_footpath_remove() +{ + rct_map_element *mapElement; + + _window_footpath_cost = MONEY32_UNDEFINED; + footpath_provisional_update(); + + mapElement = footpath_get_map_element_to_remove(); + if (mapElement != NULL) + footpath_remove_map_element(mapElement); + + window_footpath_set_enabled_and_pressed_widgets(); +} + +/** + * + * rct2: 0x006A855C + */ +static void window_footpath_set_enabled_and_pressed_widgets() +{ + rct_window *w; + uint64 pressedWidgets, disabledWidgets; + int currentRotation, direction, slope; + + w = window_find_by_class(WC_FOOTPATH); + if (w == NULL) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { + map_invalidate_map_selection_tiles(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 1) | (1 << 3); + + direction = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8); + gMapSelectionTiles[0].x = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) + TileDirectionDelta[direction].x; + gMapSelectionTiles[0].y = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) + TileDirectionDelta[direction].y; + gMapSelectionTiles[1].x = -1; + map_invalidate_map_selection_tiles(); + } + + pressedWidgets = w->pressed_widgets & 0xFFFF887F; + disabledWidgets = 0; + currentRotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) >= PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { + // Set pressed directional widget + direction = (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) + currentRotation) & 3; + pressedWidgets |= (1LL << (WIDX_DIRECTION_NW + direction)); + + // Set pressed slope widget + slope = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8); + if (slope == 6) + pressedWidgets |= (1 << WIDX_SLOPEDOWN); + else if (slope == 0) + pressedWidgets |= (1 << WIDX_LEVEL); + else + pressedWidgets |= (1 << WIDX_SLOPEUP); + + // Enable / disable directional widgets + direction = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS, uint8); + if (direction != 255) { + disabledWidgets |= + (1 << WIDX_DIRECTION_NW) | + (1 << WIDX_DIRECTION_NE) | + (1 << WIDX_DIRECTION_SW) | + (1 << WIDX_DIRECTION_SE); + + direction = (direction + currentRotation) & 3; + disabledWidgets &= ~(1 << (WIDX_DIRECTION_NW + direction)); + } + } else { + // Disable all bridge mode widgets + disabledWidgets |= + (1 << WIDX_DIRECTION_GROUP) | + (1 << WIDX_DIRECTION_NW) | + (1 << WIDX_DIRECTION_NE) | + (1 << WIDX_DIRECTION_SW) | + (1 << WIDX_DIRECTION_SE) | + (1 << WIDX_SLOPE_GROUP) | + (1 << WIDX_SLOPEDOWN) | + (1 << WIDX_LEVEL) | + (1 << WIDX_SLOPEUP) | + (1 << WIDX_CONSTRUCT) | + (1 << WIDX_REMOVE); + } + + w->pressed_widgets = pressedWidgets; + w->disabled_widgets = disabledWidgets; + window_invalidate(w); +} + +/** + * + * rct2: 0x006A7B20 + */ +static void footpath_get_next_path_info(int *type, int *x, int *y, int *z, int *slope) +{ + int direction; + + direction = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8); + *x = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) + TileDirectionDelta[direction].x; + *y = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) + TileDirectionDelta[direction].y; + *z = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) / 8; + *type = (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) << 7) + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, uint8); + *slope = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) != 0) { + *slope = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) | 4; + if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) != 2) { + *z -= 2; + *slope ^= 2; + } + } +} diff --git a/src/windows/game_bottom_toolbar.c b/src/windows/game_bottom_toolbar.c index 4374968647..9789ec2a0c 100644 --- a/src/windows/game_bottom_toolbar.c +++ b/src/windows/game_bottom_toolbar.c @@ -19,16 +19,19 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../localisation/date.h" #include "../localisation/localisation.h" #include "../interface/widget.h" #include "../interface/window.h" #include "../management/news_item.h" #include "../peep/peep.h" +#include "../peep/staff.h" #include "../sprites.h" #include "../world/climate.h" #include "../world/park.h" #include "../world/sprite.h" +#include "../interface/themes.h" enum WINDOW_GAME_BOTTOM_TOOLBAR_WIDGET_IDX { WIDX_LEFT_OUTSET, @@ -47,21 +50,26 @@ enum WINDOW_GAME_BOTTOM_TOOLBAR_WIDGET_IDX { WIDX_DATE }; + +// Right panel needs to be a bit bigger than original so dates like "22nd September, Year 126" can fit. +// Left panel size was also increased for symmetry. +#define WIDTH_MOD 22 + rct_widget window_game_bottom_toolbar_widgets[] = { - { WWT_IMGBTN, 0, 0x0000, 0x0077, 0, 33, 0xFFFFFFFF, STR_NONE }, // Left outset panel - { WWT_IMGBTN, 0, 0x0002, 0x0075, 2, 31, 0xFFFFFFFF, STR_NONE }, // Left inset panel - { WWT_FLATBTN, 0, 0x0002, 0x0075, 1, 12, 0xFFFFFFFF, STR_PROFIT_PER_WEEK_AND_PARK_VALUE_TIP }, // Money window - { WWT_FLATBTN, 0, 0x0002, 0x0075, 11, 22, 0xFFFFFFFF, STR_NONE }, // Guests window - { WWT_FLATBTN, 0, 0x0002, 0x0075, 21, 31, 0xFFFFFFFF, STR_PARK_RATING_TIP }, // Park rating window + { WWT_IMGBTN, 0, 0x0000, 0x0077+WIDTH_MOD, 0, 33, 0xFFFFFFFF, STR_NONE }, // Left outset panel + { WWT_IMGBTN, 0, 0x0002, 0x0075+WIDTH_MOD, 2, 31, 0xFFFFFFFF, STR_NONE }, // Left inset panel + { WWT_FLATBTN, 0, 0x0002, 0x0075+WIDTH_MOD, 1, 12, 0xFFFFFFFF, STR_PROFIT_PER_WEEK_AND_PARK_VALUE_TIP }, // Money window + { WWT_FLATBTN, 0, 0x0002, 0x0075+WIDTH_MOD, 11, 22, 0xFFFFFFFF, STR_NONE }, // Guests window + { WWT_FLATBTN, 0, 0x0002, 0x0075+WIDTH_MOD, 21, 31, 0xFFFFFFFF, STR_PARK_RATING_TIP }, // Park rating window - { WWT_IMGBTN, 2, 0x0078, 0x0207, 0, 33, 0xFFFFFFFF, STR_NONE }, // Middle outset panel - { WWT_25, 2, 0x007A, 0x0205, 2, 31, 0xFFFFFFFF, STR_NONE }, // Middle inset panel - { WWT_FLATBTN, 2, 0x007D, 0x0094, 5, 28, 0xFFFFFFFF, STR_SHOW_SUBJECT_TIP }, // Associated news item window - { WWT_FLATBTN, 2, 0x01EB, 0x0202, 5, 28, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, // Scroll to news item target + { WWT_IMGBTN, 2, 0x0078+WIDTH_MOD, 0x0207-WIDTH_MOD, 0, 33, 0xFFFFFFFF, STR_NONE }, // Middle outset panel + { WWT_25, 2, 0x007A+WIDTH_MOD, 0x0205-WIDTH_MOD, 2, 31, 0xFFFFFFFF, STR_NONE }, // Middle inset panel + { WWT_FLATBTN, 2, 0x007D+WIDTH_MOD, 0x0094+WIDTH_MOD, 5, 28, 0xFFFFFFFF, STR_SHOW_SUBJECT_TIP }, // Associated news item window + { WWT_FLATBTN, 2, 0x01EB-WIDTH_MOD, 0x0202-WIDTH_MOD, 5, 28, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, // Scroll to news item target - { WWT_IMGBTN, 0, 0x0208, 0x027F, 0, 33, 0xFFFFFFFF, STR_NONE }, // Right outset panel - { WWT_IMGBTN, 0, 0x020A, 0x027D, 2, 31, 0xFFFFFFFF, STR_NONE }, // Right inset panel - { WWT_FLATBTN, 0, 0x020A, 0x027D, 2, 13, 0xFFFFFFFF, 2290 }, // Date + { WWT_IMGBTN, 0, 0x0208-WIDTH_MOD, 0x027F, 0, 33, 0xFFFFFFFF, STR_NONE }, // Right outset panel + { WWT_IMGBTN, 0, 0x020A-WIDTH_MOD, 0x027D, 2, 31, 0xFFFFFFFF, STR_NONE }, // Right inset panel + { WWT_FLATBTN, 0, 0x020A-WIDTH_MOD, 0x027D, 2, 13, 0xFFFFFFFF, 2290 }, // Date { WIDGETS_END }, }; @@ -70,6 +78,9 @@ static void window_game_bottom_toolbar_mouseup(); static void window_game_bottom_toolbar_tooltip(); static void window_game_bottom_toolbar_invalidate(); static void window_game_bottom_toolbar_paint(); +static void window_game_bottom_toolbar_update(rct_window* w); +static void window_game_bottom_toolbar_cursor(); +static void window_game_bottom_toolbar_unknown05(); static void window_game_bottom_toolbar_draw_left_panel(rct_drawpixelinfo *dpi, rct_window *w); static void window_game_bottom_toolbar_draw_park_rating(rct_drawpixelinfo *dpi, rct_window *w, int colour, int x, int y, uint8 factor); @@ -77,14 +88,15 @@ static void window_game_bottom_toolbar_draw_right_panel(rct_drawpixelinfo *dpi, static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo *dpi, rct_window *w); static void window_game_bottom_toolbar_draw_tutorial_text(rct_drawpixelinfo *dpi, rct_window *w); +/* rct2: 0x0097BFDC */ static void* window_game_bottom_toolbar_events[] = { window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_mouseup, window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_emptysub, - window_game_bottom_toolbar_emptysub, - window_game_bottom_toolbar_emptysub, + window_game_bottom_toolbar_unknown05, + window_game_bottom_toolbar_update, window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_emptysub, @@ -101,7 +113,7 @@ static void* window_game_bottom_toolbar_events[] = { window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_tooltip, - window_game_bottom_toolbar_emptysub, + window_game_bottom_toolbar_cursor, window_game_bottom_toolbar_emptysub, window_game_bottom_toolbar_invalidate, window_game_bottom_toolbar_paint, @@ -138,9 +150,10 @@ void window_game_bottom_toolbar_open() window->frame_no = 0; window_init_scroll_widgets(window); - window->colours[0] = 140; - window->colours[1] = 140; - window->colours[2] = 0; + + // Reset the middle widget to not show by default. + // If it is required to be shown news_update will reshow it. + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WWT_EMPTY; } /** @@ -202,31 +215,20 @@ static void window_game_bottom_toolbar_mouseup() static void window_game_bottom_toolbar_tooltip() { int month, day; - short tool_tip_index; + short widgetIndex, result; rct_window *w; - #ifdef _MSC_VER - __asm mov tool_tip_index, ax - #else - __asm__ ( "mov %[tool_tip_index], ax " : [tool_tip_index] "+m" (tool_tip_index) ); - #endif + window_tooltip_get_registers(w, widgetIndex); - #ifdef _MSC_VER - __asm mov w, esi - #else - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); - #endif - - - switch (tool_tip_index) { + switch (widgetIndex) { case WIDX_MONEY: RCT2_GLOBAL(0x013CE952, int) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PROFIT, sint32); RCT2_GLOBAL(0x013CE956, int) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, sint32); - tool_tip_index = 0; + result = 0; break; case WIDX_PARK_RATING: RCT2_GLOBAL(0x013CE952, short) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16); - tool_tip_index = 0; + result = 0; break; case WIDX_DATE: month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7; @@ -234,15 +236,11 @@ static void window_game_bottom_toolbar_tooltip() RCT2_GLOBAL(0x013CE952, short) = STR_DATE_DAY_1 + day; RCT2_GLOBAL(0x013CE954, short) = STR_MONTH_MARCH + month; - tool_tip_index = 0; + result = 0; break; } -#ifdef _MSC_VER - __asm mov ax, tool_tip_index -#else - __asm__("mov ax, %[tool_tip_index] " :[tool_tip_index] "+m" (tool_tip_index)); -#endif + window_tooltip_set_registers(result); } /** @@ -256,6 +254,7 @@ static void window_game_bottom_toolbar_invalidate() rct_news_item *newsItem; window_get_register(w); + colour_scheme_update(w); // Anchor the middle and right panel to the right x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); @@ -264,7 +263,7 @@ static void window_game_bottom_toolbar_invalidate() window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right = x; x -= 2; window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].right = x; - x -= 115; + x -= (115 + WIDTH_MOD); window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].left = x; x -= 2; window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left = x; @@ -422,7 +421,7 @@ static void window_game_bottom_toolbar_draw_left_panel(rct_drawpixelinfo *dpi, r window_game_bottom_toolbar_draw_park_rating( dpi, w, - 14, + w->colours[3], w->x + window_game_bottom_toolbar_widgets[WIDX_PARK_RATING].left + 11, w->y + window_game_bottom_toolbar_widgets[WIDX_PARK_RATING].top, max(10, ((RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16) / 4) * 263) / 256) @@ -437,16 +436,16 @@ static void window_game_bottom_toolbar_draw_park_rating(rct_drawpixelinfo *dpi, { short bar_width; - bar_width = (factor * 90) / 256; - gfx_fill_rect_inset(dpi, x, y + 1, x + 93, y + 9, w->colours[1], 48); - if (!(colour & 0x80000000) || RCT2_GLOBAL(0x009DEA6E, uint8) != 0 || (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint8) & 8)) { + bar_width = (factor * (90 + WIDTH_MOD)) / 256; + gfx_fill_rect_inset(dpi, x, y + 1, x + (93 + WIDTH_MOD), y + 9, w->colours[1], 48); + if (!(colour & 0x80000000) || RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 || (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint8) & 8)) { if (bar_width > 2) gfx_fill_rect_inset(dpi, x + 2, y + 2, x + bar_width - 1, y + 8, colour & 0x7FFFFFFF, 0); } // Draw thumbs on the sides gfx_draw_sprite(dpi, SPR_RATING_LOW, x - 14, y, 0); - gfx_draw_sprite(dpi, SPR_RATING_HIGH, x + 92, y, 0); + gfx_draw_sprite(dpi, SPR_RATING_HIGH, x + (92 + WIDTH_MOD), y, 0); } static void window_game_bottom_toolbar_draw_right_panel(rct_drawpixelinfo *dpi, rct_window *w) @@ -468,20 +467,22 @@ static void window_game_bottom_toolbar_draw_right_panel(rct_drawpixelinfo *dpi, y = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top + w->y + 2; // Date - char *freeStr = (char*)0x009BC677; - freeStr[0] = FORMAT_STRINGID; - freeStr[1] = ' '; - freeStr[2] = FORMAT_MONTHYEAR; - freeStr[3] = 0; - - int month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7; + int year = date_get_year(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16)) + 1; + int month = date_get_month(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7); int day = ((RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) * days_in_month[month]) >> 16) & 0xFF; - - RCT2_GLOBAL(0x013CE952, short) = STR_DATE_DAY_1 + day; - RCT2_GLOBAL(0x013CE954, short) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16); + if (gConfigGeneral.date_format) { + RCT2_GLOBAL(0x013CE952, short) = month; + RCT2_GLOBAL(0x013CE954, short) = STR_DATE_DAY_1 + day; + } + else { + RCT2_GLOBAL(0x013CE952, short) = STR_DATE_DAY_1 + day; + RCT2_GLOBAL(0x013CE954, short) = month; + } + + RCT2_GLOBAL(0x013CE956, short) = year; gfx_draw_string_centred( dpi, - 3165, + (gConfigGeneral.date_format ? 5160 : 2737), x, y, (RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass) == 2 && RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, sint32) == WIDX_DATE ? 2 : w->colours[0] & 0x7F), @@ -560,105 +561,60 @@ static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo *dpi, rc if (newsItem->flags & 1) break; - /* - _edi = (int)e->paint.dpi; - _cx = x; - _dx = y; - #ifdef _MSC_VER - __asm { - mov cx, _cx - mov dx, _dx - mov esi, w - mov edi, _edi - push ebp - mov ebp, 0066C3B8h - push after - push esi - jmp ebp - after: - pop ebp + rct_drawpixelinfo* cliped_dpi = clip_drawpixelinfo(dpi, x + 1, 22, y + 1, 22); + if (!cliped_dpi) break; + + rct_peep* peep = GET_PEEP(newsItem->assoc); + int clip_x = 10, clip_y = 19; + + if (peep->type == PEEP_TYPE_STAFF){ + if (peep->staff_type == STAFF_TYPE_ENTERTAINER){ + clip_y += 3; + } } - #else - __asm__ ( "\ - \n\ - mov cx, %[_cx] \n\ - mov dx, %[_dx] \n\ - mov esi, %[w] \n\ - mov edi, %[_edi] \n\ - push ebp \n\ - mov ebp, 0x0066C3B8 \n\ - push %[after] \n\ - push esi \n\ - jmp ebp \n\ - %[after]: \n\ - pop ebp \n\ - " : [_cx] "+m" (_cx), [_dx] "+m" (_dx), [w] "+m" (w), [_edi] "+m" (_edi), [after] "+m" (after) ); - #endif - break; - */ - //_ax = x + 1; - //_cx = y + 1; - //_edi = (int)dpi; - //__asm { - // mov edi, _edi - // mov ax, _ax - // mov cx, _cx - // mov bx, 22 - // mov dx, 22 - // push ebp - //} - //sub_6EE53B(); - //__asm { - // pop ebp - // mov dpi, edi - //} - //if (dpi == NULL) - // break; + uint32 image_id_base = *RCT2_ADDRESS(0x00982708, uint32*)[peep->sprite_type * 2]; + image_id_base += w->frame_no & 0xFFFFFFFC; + image_id_base++; - //x = 10; - //y = 19; + uint32 image_id = image_id_base; + image_id |= 0xA0000000 | (peep->tshirt_colour << 19) | (peep->trousers_colour << 24); - //peep = &rctmem->sprites[*((short*)&newsItem->assoc)].peep; - //if (peep->type == PEEP_TYPE_STAFF && peep->var_2F == 3) - // y += 3; + gfx_draw_sprite(cliped_dpi, image_id, clip_x, clip_y, 0); - //_eax = *((int*)(0x00982708 + (peep->sprite_type * 8))); - //_ebx = w->frame_no & 0xFFFFFFFC; - //_ebx += *((int*)_eax); - //_ebx++; + if (image_id_base >= 0x2A1D && image_id_base < 0x2A3D){ + image_id_base += 32; + image_id_base |= 0x20000000 | (peep->balloon_colour << 19); - //gfx_draw_sprite(dpi, _ebx | (peep->var_30 << 19) | (peep->var_31 << 24) | 0xA0000000, x, y); + gfx_draw_sprite(cliped_dpi, image_id_base, clip_x, clip_y, 0); + } + else if (image_id_base >= 0x2BBD && image_id_base < 0x2BDD){ + image_id_base += 32; + image_id_base |= 0x20000000 | (peep->umbrella_colour << 19); - //if (_ebx >= 0x2A1D && _ebx >= 0x2A3D) { - // _ebx += 32; - // _ebx |= 0x20000000; - // _ebx |= peep->balloon_colour << 19; - // gfx_draw_sprite(dpi, _ebx, x, y); - //} else if (_ebx >= 0x2BBD && _ebx >= 0x2BDD) { - // _ebx += 32; - // _ebx |= 0x20000000; - // _ebx |= peep->umbrella_colour << 19; - // gfx_draw_sprite(dpi, _ebx, x, y); - //} else if (_ebx >= 0x29DD && _ebx >= 0x29FD) { - // _ebx += 32; - // _ebx |= 0x20000000; - // _ebx |= peep->hat_colour << 19; - // gfx_draw_sprite(dpi, _ebx, x, y); - //} else { + gfx_draw_sprite(cliped_dpi, image_id_base, clip_x, clip_y, 0); + } + else if (image_id_base >= 0x29DD && image_id_base < 0x29FD){ + image_id_base += 32; + image_id_base |= 0x20000000 | (peep->hat_colour << 19); - //} + gfx_draw_sprite(cliped_dpi, image_id_base, clip_x, clip_y, 0); + } + rct2_free(cliped_dpi); break; case NEWS_ITEM_MONEY: gfx_draw_sprite(dpi, SPR_FINANCE, x, y, 0); + break; case NEWS_ITEM_RESEARCH: gfx_draw_sprite(dpi, (newsItem->assoc < 0x10000 ? SPR_NEW_RIDE : SPR_SCENERY), x, y, 0); break; case NEWS_ITEM_PEEPS: gfx_draw_sprite(dpi, SPR_GUESTS, x, y, 0); + break; case NEWS_ITEM_AWARD: gfx_draw_sprite(dpi, SPR_AWARD, x, y, 0); + break; case NEWS_ITEM_GRAPH: gfx_draw_sprite(dpi, SPR_GRAPH, x, y, 0); break; @@ -674,3 +630,62 @@ static void window_game_bottom_toolbar_draw_tutorial_text(rct_drawpixelinfo *dpi gfx_draw_string_centred(dpi, STR_TUTORIAL, x, y, 32, 0); gfx_draw_string_centred(dpi, STR_PRESS_KEY_OR_MOUSE_BUTTON_FOR_CONTROL, x, y + 10, 32, 0); } + +/* rct2: 0x0066C6D8 */ +static void window_game_bottom_toolbar_update(rct_window* w){ + + w->frame_no++; + if (w->frame_no >= 24)w->frame_no = 0; + + // Due to windows not fully finished use callproc to save on duplicate code. + RCT2_CALLPROC_X((int)window_game_bottom_toolbar_unknown05, 0, 0, 0, 0, (int)w, 0, 0); +} + +/* rct2: 0x006C644 */ +static void window_game_bottom_toolbar_cursor(){ + rct_window *w; + short widgetIndex, x, y; + + window_cursor_get_registers(w, widgetIndex, x, y); + + switch (widgetIndex){ + case WIDX_MONEY: + case WIDX_GUESTS: + case WIDX_PARK_RATING: + case WIDX_DATE: + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 2000; + break; + } +} + +/* rct2: 0x0066C6F2 */ +static void window_game_bottom_toolbar_unknown05(){ + rct_window* w; + + window_get_register(w); + + if (RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) & BTM_TB_DIRTY_FLAG_MONEY){ + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) &= ~BTM_TB_DIRTY_FLAG_MONEY; + widget_invalidate(w, WIDX_LEFT_INSET); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) & BTM_TB_DIRTY_FLAG_DATE){ + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) &= ~BTM_TB_DIRTY_FLAG_DATE; + widget_invalidate(w, WIDX_RIGHT_INSET); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) & BTM_TB_DIRTY_FLAG_PEEP_COUNT){ + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) &= ~BTM_TB_DIRTY_FLAG_PEEP_COUNT; + widget_invalidate(w, WIDX_LEFT_INSET); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) & BTM_TB_DIRTY_FLAG_CLIMATE){ + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) &= ~BTM_TB_DIRTY_FLAG_CLIMATE; + widget_invalidate(w, WIDX_RIGHT_INSET); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) & BTM_TB_DIRTY_FLAG_PARK_RATING){ + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) &= ~BTM_TB_DIRTY_FLAG_PARK_RATING; + widget_invalidate(w, WIDX_LEFT_INSET); + } +} diff --git a/src/windows/game_top_toolbar.c b/src/windows/game_top_toolbar.c deleted file mode 100644 index 4241bfa49b..0000000000 --- a/src/windows/game_top_toolbar.c +++ /dev/null @@ -1,680 +0,0 @@ -/***************************************************************************** - * 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 . - *****************************************************************************/ - -#include "../addresses.h" -#include "../game.h" -#include "../input.h" -#include "../sprites.h" -#include "../toolbar.h" -#include "../audio/audio.h" -#include "../interface/widget.h" -#include "../interface/window.h" -#include "../interface/viewport.h" -#include "../localisation/localisation.h" -#include "dropdown.h" -#include "scenery.h" - -enum { - WIDX_PAUSE, - WIDX_FILE_MENU, - WIDX_ZOOM_OUT, - WIDX_ZOOM_IN, - WIDX_ROTATE, - WIDX_VIEW_MENU, - WIDX_MAP, - - WIDX_LAND, - WIDX_WATER, - WIDX_SCENERY, - WIDX_PATH, - WIDX_CONSTRUCT_RIDE, - WIDX_RIDES, - WIDX_PARK, - WIDX_STAFF, - WIDX_GUESTS, - WIDX_CLEAR_SCENERY, - - //WIDX_FASTFORWARD, - WIDX_RESEARCH -}; - -typedef enum { - DDIDX_LOAD_GAME = 0, - DDIDX_SAVE_GAME = 1, - DDIDX_ABOUT = 3, - DDIDX_OPTIONS = 4, - DDIDX_SCREENSHOT = 5, - DDIDX_QUIT_GAME = 7, -} FILE_MENU_DDIDX; - -static rct_widget window_game_top_toolbar_widgets[] = { - { WWT_TRNBTN, 0, 0x0000, 0x001D, 0, 27, 0x20000000 | SPR_TOOLBAR_PAUSE, STR_PAUSE_GAME_TIP }, // Pause - { WWT_TRNBTN, 0, 0x001E + 30, 0x003B + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_FILE, STR_DISC_AND_GAME_OPTIONS_TIP }, // File menu - { WWT_TRNBTN, 1, 0x0046 + 30, 0x0063 + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_ZOOM_OUT, STR_ZOOM_OUT_TIP }, // Zoom out - { WWT_TRNBTN, 1, 0x0064 + 30, 0x0081 + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_ZOOM_IN, STR_ZOOM_IN_TIP }, // Zoom in - { WWT_TRNBTN, 1, 0x0082 + 30, 0x009F + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_ROTATE, STR_ROTATE_TIP }, // Rotate camera - { WWT_TRNBTN, 1, 0x00A0 + 30, 0x00BD + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_VIEW, STR_VIEW_OPTIONS_TIP }, // Transparancy menu - { WWT_TRNBTN, 1, 0x00BE + 30, 0x00DB + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_MAP, STR_SHOW_MAP_TIP }, // Map - - { WWT_TRNBTN, 2, 0x010B, 0x0128, 0, 27, 0x20000000 | SPR_TOOLBAR_LAND, STR_ADJUST_LAND_TIP }, // Land - { WWT_TRNBTN, 2, 0x0129, 0x0146, 0, 27, 0x20000000 | SPR_TOOLBAR_WATER, STR_ADJUST_WATER_TIP }, // Water - { WWT_TRNBTN, 2, 0x0147, 0x0164, 0, 27, 0x20000000 | SPR_TOOLBAR_SCENERY, STR_PLACE_SCENERY_TIP }, // Scenery - { WWT_TRNBTN, 2, 0x0165, 0x0182, 0, 27, 0x20000000 | SPR_TOOLBAR_FOOTPATH, STR_BUILD_FOOTPATH_TIP }, // Path - { WWT_TRNBTN, 2, 0x0183, 0x01A0, 0, 27, 0x20000000 | SPR_TOOLBAR_CONSTRUCT_RIDE, STR_BUILD_RIDE_TIP }, // Construct ride - { WWT_TRNBTN, 3, 0x01EA, 0x0207, 0, 27, 0x20000000 | SPR_TOOLBAR_RIDES, STR_RIDES_IN_PARK_TIP }, // Rides - { WWT_TRNBTN, 3, 0x0208, 0x0225, 0, 27, 0x20000000 | SPR_TOOLBAR_PARK, STR_PARK_INFORMATION_TIP }, // Park - { WWT_TRNBTN, 3, 0x0226, 0x0243, 0, 27, 0x20000000 | 0x15F9, STR_STAFF_TIP }, // Staff - { WWT_TRNBTN, 3, 0x0230, 0x024D, 0, 27, 0x20000000 | SPR_TOOLBAR_GUESTS, STR_GUESTS_TIP }, // Guests - { WWT_TRNBTN, 2, 0x0230, 0x024D, 0, 27, 0x20000000 | SPR_TOOLBAR_CLEAR_SCENERY, STR_CLEAR_SCENERY_TIP }, // Clear scenery - - //{ WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_NONE }, // Fast forward - { WWT_TRNBTN, 3, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, 2275 }, // Research - { WIDGETS_END }, -}; - -static void window_game_top_toolbar_emptysub() { } -static void window_game_top_toolbar_mouseup(); -static void window_game_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_game_top_toolbar_dropdown(); -static void window_game_top_toolbar_tool_update(); -static void window_game_top_toolbar_tool_down(); -static void window_game_top_toolbar_tool_drag(); -static void window_game_top_toolbar_invalidate(); -static void window_game_top_toolbar_paint(); - -static void* window_game_top_toolbar_events[] = { - window_game_top_toolbar_emptysub, - window_game_top_toolbar_mouseup, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_mousedown, - window_game_top_toolbar_dropdown, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_tool_update, - window_game_top_toolbar_tool_down, - window_game_top_toolbar_tool_drag, - (void*)0x0066CC5B, - (void*)0x0066CA58, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_emptysub, - window_game_top_toolbar_invalidate, - window_game_top_toolbar_paint, - window_game_top_toolbar_emptysub -}; - -/** - * Creates the main game top toolbar window. - * rct2: 0x0066B485 (part of 0x0066B3E8) - */ -void window_game_top_toolbar_open() -{ - rct_window* window; - - window = window_create( - 0, 0, - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), 28, - (uint32*)window_game_top_toolbar_events, - WC_TOP_TOOLBAR, - WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5 - ); - window->widgets = window_game_top_toolbar_widgets; - - window->enabled_widgets |= - (1 << WIDX_PAUSE) | - (1 << WIDX_FILE_MENU) | - (1 << WIDX_ZOOM_OUT) | - (1 << WIDX_ZOOM_IN) | - (1 << WIDX_ROTATE) | - (1 << WIDX_VIEW_MENU) | - (1 << WIDX_MAP) | - (1 << WIDX_LAND) | - (1 << WIDX_WATER) | - (1 << WIDX_SCENERY) | - (1 << WIDX_PATH) | - (1 << WIDX_CONSTRUCT_RIDE) | - (1 << WIDX_RIDES) | - (1 << WIDX_PARK) | - (1 << WIDX_STAFF) | - (1 << WIDX_GUESTS) | - (1 << WIDX_CLEAR_SCENERY) | - //(1ULL << WIDX_FASTFORWARD) | - (1ULL << WIDX_RESEARCH); - - window_init_scroll_widgets(window); - window->colours[0] = 7; - window->colours[1] = 12; - window->colours[2] = 24; - window->colours[3] = 1; -} - -/** - * - * rct2: 0x0066C957 - */ -static void window_game_top_toolbar_mouseup() -{ - short widgetIndex; - rct_window *w, *mainWindow; - - window_widget_get_registers(w, widgetIndex); - - switch (widgetIndex) { - case WIDX_PAUSE: - game_do_command(0, 1, 0, 0, GAME_COMMAND_TOGGLE_PAUSE, 0, 0); - break; - // case WIDX_FASTFORWARD: - // // This is an excellent place to add in debugging statements and - // // print routines, that will be triggered when you press the - // // button in the game. Use "git update-index --skip-worktree - // // src/window_game_top_toolbar" to avoid committing these changes to - // // version control. - // window_cheats_open(); - // break; - - case WIDX_ZOOM_OUT: - if ((mainWindow = window_get_main()) != NULL) - window_zoom_out(mainWindow); - break; - case WIDX_ZOOM_IN: - if ((mainWindow = window_get_main()) != NULL) - window_zoom_in(mainWindow); - break; - case WIDX_ROTATE: - if ((mainWindow = window_get_main()) != NULL) - window_rotate_camera(mainWindow); - break; - case WIDX_CLEAR_SCENERY: - toggle_clear_scenery_window(w, WIDX_CLEAR_SCENERY); - break; - case WIDX_LAND: - toggle_land_window(w, WIDX_LAND); - break; - case WIDX_WATER: - toggle_water_window(w, WIDX_WATER); - break; - case WIDX_SCENERY: - if (!tool_set(w, WIDX_SCENERY, 0)) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; - window_scenery_open(); - } - break; - case WIDX_PATH: - toggle_footpath_window(); - break; - case WIDX_CONSTRUCT_RIDE: - window_new_ride_open(); - break; - case WIDX_RIDES: - window_ride_list_open(); - break; - case WIDX_PARK: - window_park_entrance_open(); - break; - case WIDX_STAFF: - window_staff_list_open(); - break; - case WIDX_GUESTS: - window_guest_list_open(); - break; - case WIDX_RESEARCH: - window_research_open(); - break; - } -} - -/** - * - * rct2: 0x0066CA3B - */ -static void window_game_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) -{ - switch (widgetIndex) { - case WIDX_FILE_MENU: - gDropdownItemsFormat[0] = STR_LOAD_GAME; - gDropdownItemsFormat[1] = STR_SAVE_GAME; - gDropdownItemsFormat[2] = 0; - gDropdownItemsFormat[3] = STR_ABOUT; - gDropdownItemsFormat[4] = STR_OPTIONS; - gDropdownItemsFormat[5] = STR_SCREENSHOT; - gDropdownItemsFormat[6] = 0; - gDropdownItemsFormat[7] = STR_QUIT_GAME; - window_dropdown_show_text( - w->x + widget->left, - w->y + widget->top, - widget->bottom - widget->top + 1, - w->colours[0] | 0x80, - 0x80, - 8 - ); - break; - case WIDX_VIEW_MENU: - top_toolbar_init_view_menu(w, widget); - break; - case WIDX_MAP: - gDropdownItemsFormat[0] = 2523; - gDropdownItemsFormat[1] = 2780; - window_dropdown_show_text( - w->x + widget->left, - w->y + widget->top, - widget->bottom - widget->top + 1, - w->colours[1] | 0x80, - 0, - 2 - ); - RCT2_GLOBAL(0x9DEBA2, uint16) = 0; - break; - } -} - -/** - * - * rct2: 0x0066C9EA - */ -static void window_game_top_toolbar_dropdown() -{ - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - - switch (widgetIndex) { - case WIDX_FILE_MENU: - switch (dropdownIndex) { - case DDIDX_LOAD_GAME: // load game - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); - break; - case DDIDX_SAVE_GAME: // save game - tool_cancel(); - save_game(); - break; - case DDIDX_ABOUT: // about - window_about_open(); - break; - case DDIDX_OPTIONS: // options - window_options_open(); - break; - case DDIDX_SCREENSHOT: // screenshot - RCT2_GLOBAL(RCT2_ADDRESS_SCREENSHOT_COUNTDOWN, sint8) = 10; - break; - case DDIDX_QUIT_GAME: // quit game - game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); - break; - } - break; - case WIDX_VIEW_MENU: - top_toolbar_view_menu_dropdown(dropdownIndex); - break; - case WIDX_MAP: - if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x9DEBA2, uint16); - switch (dropdownIndex) { - case 0: - window_map_open(); - break; - case 1: - window_viewport_open(); - break; - } - break; - } -} - -/** - * - * rct2: 0x0066C810 - */ -static void window_game_top_toolbar_invalidate() -{ - int x; - rct_window *w; - - window_get_register(w); - - // Anchor the right half of the buttons to the right - x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - if (x < 640) - x = 640; - x--; - window_game_top_toolbar_widgets[WIDX_GUESTS].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_GUESTS].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_STAFF].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_STAFF].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_PARK].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_PARK].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_RIDES].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_RIDES].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_RESEARCH].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_RESEARCH].left = x; - x -= 11; - window_game_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_PATH].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_PATH].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_SCENERY].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_SCENERY].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_WATER].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_WATER].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_LAND].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_LAND].left = x; - x -= 1; - window_game_top_toolbar_widgets[WIDX_CLEAR_SCENERY].right = x; - x -= 29; - window_game_top_toolbar_widgets[WIDX_CLEAR_SCENERY].left = x; - x = 0; - window_game_top_toolbar_widgets[WIDX_PAUSE].left = x; - x += 29; - window_game_top_toolbar_widgets[WIDX_PAUSE].right = x; - // x += 1; - // window_game_top_toolbar_widgets[WIDX_FASTFORWARD].left = x; - // x += 29; - // window_game_top_toolbar_widgets[WIDX_FASTFORWARD].right = x; - x += 1; - window_game_top_toolbar_widgets[WIDX_FILE_MENU].left = x; - x += 29; - window_game_top_toolbar_widgets[WIDX_FILE_MENU].right = x; - x += 11; - window_game_top_toolbar_widgets[WIDX_ZOOM_OUT].left = x; - x += 29; - window_game_top_toolbar_widgets[WIDX_ZOOM_OUT].right = x; - x += 1; - window_game_top_toolbar_widgets[WIDX_ZOOM_IN].left = x; - x += 29; - window_game_top_toolbar_widgets[WIDX_ZOOM_IN].right = x; - x += 1; - window_game_top_toolbar_widgets[WIDX_ROTATE].left = x; - x += 29; - window_game_top_toolbar_widgets[WIDX_ROTATE].right = x; - x += 1; - window_game_top_toolbar_widgets[WIDX_VIEW_MENU].left = x; - x += 29; - window_game_top_toolbar_widgets[WIDX_VIEW_MENU].right = x; - x += 1; - window_game_top_toolbar_widgets[WIDX_MAP].left = x; - x += 29; - window_game_top_toolbar_widgets[WIDX_MAP].right = x; - - // Footpath button pressed down - if (window_find_by_class(WC_FOOTPATH) == NULL) - w->pressed_widgets &= ~(1 << WIDX_PATH); - else - w->pressed_widgets |= (1 << WIDX_PATH); - - // Fast forward button pressed down - // if (0) - // w->pressed_widgets |= (1 << WIDX_FASTFORWARD); - // else - // w->pressed_widgets &= ~(1 << WIDX_FASTFORWARD); - - if (!(RCT2_GLOBAL(0x009DEA6E, uint32) & 1)) - w->pressed_widgets &= ~(1 << WIDX_PAUSE); - else - w->pressed_widgets |= (1 << WIDX_PAUSE); - - // Zoomed out/in disable. Not sure where this code is in the original. - if (window_get_main()->viewport->zoom == 0){ - w->disabled_widgets |= (1 << WIDX_ZOOM_IN); - } - else if (window_get_main()->viewport->zoom == 3){ - w->disabled_widgets |= (1 << WIDX_ZOOM_OUT); - } - else - { - w->disabled_widgets &= ~((1 << WIDX_ZOOM_IN) | (1 << WIDX_ZOOM_OUT)); - } -} - -/** - * - * rct2: 0x0066C8EC - */ -static void window_game_top_toolbar_paint() -{ - int x, y, imgId; - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - - window_draw_widgets(w, dpi); - - // Draw staff button image (setting masks to the staff colours) - x = w->x + window_game_top_toolbar_widgets[WIDX_STAFF].left; - y = w->y + window_game_top_toolbar_widgets[WIDX_STAFF].top; - imgId = 5627; - if (widget_is_pressed(w, WIDX_STAFF)) - imgId++; - imgId |= (RCT2_GLOBAL(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8) << 19) | 0xA0000000 | (RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) << 24); - gfx_draw_sprite(dpi, imgId, x, y, 0); - - // Draw research button - x = w->x + window_game_top_toolbar_widgets[WIDX_RESEARCH].left - 1; - y = w->y + window_game_top_toolbar_widgets[WIDX_RESEARCH].top - 1; - imgId = SPR_TAB_FINANCES_RESEARCH_0; - gfx_draw_sprite(dpi, imgId, x, y, 0); -} - -/** - * rct2: 0x6e2cc6 - */ -static void window_game_top_toolbar_scenery_tool_down(short x, short y, rct_window* w, short widgetIndex){ - RCT2_CALLPROC_EBPSAFE(0x006E2712); - if (window_scenery_is_repaint_scenery_tool_on & 1){ - //6e3158 - RCT2_CALLPROC_X(0x6E2CC6, x, y, 0, widgetIndex, (int)w, 0, 0); - } - - int selected_tab = window_scenery_selected_scenery_by_tab[window_scenery_active_tab_index]; - if (selected_tab == -1) return; - - sint16 grid_x, grid_y, grid_z; - uint8 item_colour; - uint8 model_type; - int ebp = selected_tab; - - { - int eax = x, ebx = y, ecx = 0, edx = 0, esi = 0, edi = 0; - RCT2_CALLFUNC_X(0x6E1F34, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - item_colour = edi; - model_type = (ebx & 0xFF00) >> 8; - grid_x = eax; - grid_y = ecx; - grid_z = edx; - } - - if (grid_x == 0x8000)return; - - if (ebp >= 1024){ - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1161; - - // The return value will be banner id but the input is colour - int banner_id = item_colour; - - int ebx = (model_type << 8) | 1; - - { - int esi = 0, eax = grid_x, ecx = grid_y, edx = grid_z; - game_do_command_p(GAME_COMMAND_50, &eax, &ebx, &ecx, &edx, &esi, &banner_id, &ebp); - } - - if (ebx == 0x80000000)return; - - sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); - - window_banner_open(banner_id); - } - else if (ebp >= 768){ - //6e301c - RCT2_CALLPROC_X(0x6E2CC6, x, y, 0, widgetIndex, (int)w, 0, 0); - } - else if (ebp >= 512){ - //6e2f2e - RCT2_CALLPROC_X(0x6E2CC6, x, y, 0, widgetIndex, (int)w, 0, 0); - } - else if (ebp >= 256){ - //6e2eda - RCT2_CALLPROC_X(0x6E2CC6, x, y, 0, widgetIndex, (int)w, 0, 0); - } - else{ - //6e2d2d - RCT2_CALLPROC_X(0x6E2CC6, x, y, 0, widgetIndex, (int)w, 0, 0); - } -} - -/** - * - * rct2: 0x0066CB25 - */ -static void window_game_top_toolbar_tool_update() -{ - short widgetIndex; - rct_window *w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - switch (widgetIndex){ - case WIDX_CLEAR_SCENERY: - RCT2_CALLPROC_X(0x0068E213, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_LAND: - RCT2_CALLPROC_X(0x00664280, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_WATER: - RCT2_CALLPROC_X(0x006E6BDC, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_SCENERY: - RCT2_CALLPROC_X(0x006E287B, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - } -} - -/** - * rct2: 0x0066CB73 - */ -static void window_game_top_toolbar_tool_down(){ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - switch (widgetIndex){ - case WIDX_CLEAR_SCENERY: - if (!RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0)) - break; - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3438; - - game_do_command( - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16), - 1, - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16), - 0, - GAME_COMMAND_CLEAR_SCENERY, - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16), - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) - ); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 12; - break; - case WIDX_LAND: - RCT2_CALLPROC_X(0x66CBF3, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_WATER: - RCT2_CALLPROC_X(0x66CC48, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_SCENERY: - window_game_top_toolbar_scenery_tool_down(x, y, w, widgetIndex); - break; - } -} - -/** - * - * rct2: 0x0066CB4E - */ -static void window_game_top_toolbar_tool_drag() -{ - short widgetIndex; - rct_window *w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - switch (widgetIndex){ - case WIDX_CLEAR_SCENERY: - if (window_find_by_class(WC_ERROR) != NULL) - break; - - if (!RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0)) - break; - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3438; - - game_do_command( - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16), - 1, - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16), - 0, - GAME_COMMAND_CLEAR_SCENERY, - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16), - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) - ); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 12; - break; - case WIDX_LAND: - RCT2_CALLPROC_X(0x00664454, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_WATER: - RCT2_CALLPROC_X(0x006E6D4B, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_SCENERY: - RCT2_CALLPROC_X(0x006E2CBC, x, y, 0, widgetIndex, (int)w, 0, 0); - break; - } -} \ No newline at end of file diff --git a/src/windows/guest.c b/src/windows/guest.c index 68de0e5576..d5b9467b55 100644 --- a/src/windows/guest.c +++ b/src/windows/guest.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../world/map.h" #include "../management/marketing.h" @@ -32,8 +33,11 @@ #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../world/footpath.h" +#include "../input.h" #include "dropdown.h" #include "error.h" +#include "../interface/themes.h" enum WINDOW_GUEST_PAGE { WINDOW_GUEST_OVERVIEW, @@ -73,7 +77,7 @@ rct_widget window_guest_overview_widgets[] = { { WWT_FRAME, 0, 0, 191, 0, 156, 0x0FFFFFFFF, STR_NONE }, // Panel / Background { WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP }, // Title { WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // Close x button - { WWT_RESIZE, 1, 1, 191, 43, 156, 0x0FFFFFFFF, STR_NONE }, // Resize + { WWT_RESIZE, 1, 0, 191, 43, 156, 0x0FFFFFFFF, STR_NONE }, // Resize { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938 }, // Tab 1 { WWT_TAB, 1, 73, 64, 17, 43, 0x2000144E, 1940}, // Tab 2 { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, // Tab 3 @@ -416,6 +420,8 @@ void* window_guest_page_events[] = { window_guest_inventory_events }; +void window_guest_set_colours(); + //0x981D3C uint32 window_guest_page_enabled_widgets[] = { (1 << WIDX_CLOSE) | @@ -487,7 +493,7 @@ void window_guest_open(rct_peep* peep){ window = window_bring_to_front_by_number(WC_PEEP, peep->sprite_index); if (window == NULL){ - window = window_create_auto_pos(192, 157, (uint32*)window_guest_overview_events, WC_PEEP, 0); + window = window_create_auto_pos(192, 157, (uint32*)window_guest_overview_events, WC_PEEP, WF_RESIZABLE); window->widgets = window_guest_overview_widgets; window->enabled_widgets = window_guest_page_enabled_widgets[0]; window->number = peep->sprite_index; @@ -502,12 +508,9 @@ void window_guest_open(rct_peep* peep){ window->min_height = 157; window->max_width = 500; window->max_height = 450; - window->flags = WF_RESIZABLE; window->no_list_items = 0; window->selected_list_item = -1; - window->colours[0] = 1; - window->colours[1] = 15; - window->colours[2] = 15; + window->viewport_focus_coordinates.y = -1; } @@ -516,7 +519,7 @@ void window_guest_open(rct_peep* peep){ window->widgets = window_guest_page_widgets[WINDOW_GUEST_OVERVIEW]; window->enabled_widgets = window_guest_page_enabled_widgets[WINDOW_GUEST_OVERVIEW]; - window->var_020 = RCT2_GLOBAL(0x981D54,uint32); + window->hold_down_widgets = 0; window->event_handlers = window_guest_page_events[WINDOW_GUEST_OVERVIEW]; window->pressed_widgets = 0; @@ -554,7 +557,7 @@ void window_guest_overview_close(){ window_get_register(w); - if (RCT2_GLOBAL(0x9DE518,uint32) & (1<<3)){ + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE){ if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS,rct_windowclass) && w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER,rct_windownumber)) tool_cancel(); @@ -568,7 +571,7 @@ void window_guest_overview_resize(){ window_get_register(w); window_guest_disable_widgets(w); - RCT2_CALLPROC_EBPSAFE(w->event_handlers[WE_INVALIDATE]); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_MARQUEE); @@ -621,17 +624,17 @@ void window_guest_overview_mouse_up(){ w->var_48C = peep->x; - RCT2_CALLPROC_X(0x0069A512, 0, 0, 0, 0, (int)peep, 0, 0); + remove_peep_from_ride(peep); invalidate_sprite((rct_sprite*)peep); sprite_move(0x8000, peep->y, peep->z, (rct_sprite*)peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_PICKED; - peep->var_2C = 0; + peep->sub_state = 0; peep_window_state_update(peep); break; case WIDX_RENAME: - window_text_input_open(w, widgetIndex, 0x5AC, 0x5AD, peep->name_string_idx, peep->id); + window_text_input_open(w, widgetIndex, 0x5AC, 0x5AD, peep->name_string_idx, peep->id, 32); break; case WIDX_LOCATE: window_scroll_to_viewport(w); @@ -644,7 +647,7 @@ void window_guest_overview_mouse_up(){ /* rct2: 0x696AA0 */ void window_guest_set_page(rct_window* w, int page){ - if (RCT2_GLOBAL(0x9DE518,uint32) & (1 << 3)) + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) @@ -670,16 +673,14 @@ void window_guest_set_page(rct_window* w, int page){ } w->enabled_widgets = window_guest_page_enabled_widgets[page]; - w->var_020 = RCT2_ADDRESS(0x981D54,uint32)[page]; + w->hold_down_widgets = 0; w->event_handlers = window_guest_page_events[page]; w->pressed_widgets = 0; w->widgets = window_guest_page_widgets[page]; window_guest_disable_widgets(w); window_invalidate(w); - - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); - + window_event_resize_call(w); + window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); @@ -730,7 +731,7 @@ void window_guest_viewport_init(rct_window* w){ } if (peep->x == SPRITE_LOCATION_NULL && final_check){ rct_ride* ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[peep->current_ride]); - int x = ride->overall_view & 0xFF * 32 + 16; + int x = (ride->overall_view & 0xFF) * 32 + 16; int y = (ride->overall_view >> 8) * 32 + 16; int height = map_element_height(x, y); height += 32; @@ -768,7 +769,7 @@ void window_guest_viewport_init(rct_window* w){ viewport_flags |= VIEWPORT_FLAG_GRIDLINES; } - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); w->viewport_focus_coordinates.x = focus.coordinate.x; w->viewport_focus_coordinates.y = focus.coordinate.y; @@ -854,6 +855,8 @@ void window_guest_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ ebx |= (peep->hat_colour << 19) | 0x20000000; gfx_draw_sprite( clip_dpi, ebx, x, y, 0); } + + rct2_free(clip_dpi); } /* rct2: 0x69869b */ @@ -1017,12 +1020,15 @@ void window_guest_overview_paint(){ x = widget->right - widget->left - w->list_information_type; gfx_draw_string_left(dpi_marquee, 1193, (void*)0x13CE952, 0, x, 0); + + rct2_free(dpi_marquee); } /* rct2: 0x696749*/ void window_guest_overview_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ w->widgets = window_guest_page_widgets[w->page]; @@ -1099,11 +1105,9 @@ void window_guest_overview_update(rct_window* w){ if (rand <= 0x2AAA){ rct_peep* peep = GET_PEEP(w->number); peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_WATCHED, 0xFF); - //RCT2_CALLPROC_X(0x699F5A, 0xFF00 | PEEP_THOUGHT_TYPE_WATCHED, 0, 0, 0, (int)peep, 0, 0); } } } - } /* rct2:0x696A6A */ @@ -1136,28 +1140,27 @@ void window_guest_overview_tool_update(){ if (widgetIndex != WIDX_PICKUP) return; - RCT2_CALLPROC_X(0x0068AAE1, x, y, 0, 0, (int)w, 0, 0); + map_invalidate_selection_rect(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); - int temp_y = y + 16; - int eax = x, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - RCT2_CALLFUNC_X(0x689726, &eax, &temp_y, &ecx, &edx, &esi, &edi, &ebp); - if (eax != 0x8000){ + int map_x, map_y; + footpath_get_coordinates_from_pos(x, y + 16, &map_x, &map_y, NULL, NULL); + if (map_x != (sint16)0x8000){ RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = eax; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = temp_y; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = temp_y; - RCT2_CALLPROC_X(0x0068AAE1, eax, temp_y, 0, 0, (int)w, 0, 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = map_x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = map_y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = map_y; + map_invalidate_selection_rect(); } RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; - int ebx; - get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &ebx, NULL); - if (ebx == 0) + int interactionType; + get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_NONE, NULL, NULL, &interactionType, NULL, NULL); + if (interactionType == VIEWPORT_INTERACTION_ITEM_NONE) return; x--; @@ -1169,11 +1172,11 @@ void window_guest_overview_tool_update(){ rct_peep* peep; peep = GET_PEEP(w->number); - ebx = (RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2])[22]; + int ebx = (RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2])[22]; ebx += w->var_492 >> 2; - ebp = peep->tshirt_colour << 19; - ecx = peep->trousers_colour << 24; + int ebp = peep->tshirt_colour << 19; + int ecx = peep->trousers_colour << 24; ebx |= ebp | ecx | 0xA0000000; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) = ebx; @@ -1189,11 +1192,11 @@ void window_guest_overview_tool_down(){ if (widgetIndex != WIDX_PICKUP) return; - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - dest_y += 16; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + rct_map_element *mapElement; + footpath_get_coordinates_from_pos(x, y + 16, &dest_x, &dest_y, NULL, &mapElement); - if (dest_x == 0x8000)return; + if (dest_x == (sint16)0x8000)return; // Set the coordinate of destination to be exactly // in the middle of a tile. @@ -1203,9 +1206,9 @@ void window_guest_overview_tool_down(){ int tile_y = dest_y & 0xFFE0; int tile_x = dest_x & 0xFFE0; - int dest_z = ((uint8*)edx)[2] * 8 + 16; + int dest_z = mapElement->base_height * 8 + 16; - if (!sub_664F72(tile_x, tile_y, dest_z)){ + if (!map_is_location_owned(tile_x, tile_y, dest_z)){ window_error_open(0x785,-1); return; } @@ -1231,12 +1234,11 @@ void window_guest_overview_tool_down(){ peep_window_state_update(peep); peep->action = 0xFF; peep->var_6D = 0; - peep->var_70 = 0; - peep->var_6E = 0xFF; + peep->action_sprite_image_offset = 0; + peep->action_sprite_type = 0xFF; peep->var_C4 = 0; - peep->happiness_growth_rate -= 10; - if (peep->happiness_growth_rate < 0)peep->happiness_growth_rate = 0; + peep->happiness_growth_rate = max(peep->happiness_growth_rate - 10, 0); sub_693B58(peep); tool_cancel(); @@ -1258,14 +1260,14 @@ void window_guest_overview_tool_abort(){ sprite_move( w->var_48C, peep->y, peep->z + 8, (rct_sprite*)peep); invalidate_sprite((rct_sprite*)peep); - if (peep->x != 0x8000){ + if (peep->x != (sint16)0x8000){ peep_decrement_num_riders(peep); peep->state = 0; peep_window_state_update(peep); peep->action = 0xFF; peep->var_6D = 0; - peep->var_70 = 0; - peep->var_6E = 0; + peep->action_sprite_image_offset = 0; + peep->action_sprite_type = 0; peep->var_C4 = 0; } @@ -1329,6 +1331,7 @@ void window_guest_stats_update(){ void window_guest_stats_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_guest_page_widgets[w->page]) { w->widgets = window_guest_page_widgets[w->page]; @@ -1362,8 +1365,6 @@ void window_guest_stats_invalidate(){ * ebp: colour, contains flag 0x80000000 for blinking */ void window_guest_stats_bars_paint(int value, int x, int y, rct_window *w, rct_drawpixelinfo *dpi, int colour){ - //RCT2_CALLPROC_X(0x6974FC, value, 0, x, y, (int)w, (int)dpi, colour); - value *= 0x76; value >>= 8; @@ -1372,7 +1373,7 @@ void window_guest_stats_bars_paint(int value, int x, int y, rct_window *w, rct_d int blink_flag = colour & (1 << 0x1F); //0x80000000 colour &= ~(1 << 0x1F); if (!blink_flag || - RCT2_GLOBAL(0x009DEA6E, uint8) != 0 || + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 || (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 8) == 0) { if (value <= 2) @@ -1565,7 +1566,7 @@ void window_guest_rides_update(){ uint8 curr_list_position = 0; for (uint8 ride_id = 0; ride_id < 255; ++ride_id){ // Offset to the ride_id bit in peep_rides_been_on - uint8 ride_id_bit = ride_id & 0x3; + uint8 ride_id_bit = ride_id & 0x7; uint8 ride_id_offset = ride_id / 8; if (peep->rides_been_on[ride_id_offset] & (1 << ride_id_bit)){ rct_ride* ride = GET_RIDE(ride_id); @@ -1588,12 +1589,15 @@ void window_guest_rides_tooltip(){ } /* rct2: 0x69784E */ -void window_guest_rides_scroll_get_size(){ +void window_guest_rides_scroll_get_size() +{ rct_window *w; + int width, height; window_get_register(w); - int height = w->no_list_items * 10; + width = 0; + height = w->no_list_items * 10; if (w->selected_list_item != -1){ w->selected_list_item = -1; @@ -1612,26 +1616,16 @@ void window_guest_rides_scroll_get_size(){ window_invalidate(w); } -#ifdef _MSC_VER - __asm mov ecx, 0 -#else - __asm__("mov ecx, 0 "); -#endif - -#ifdef _MSC_VER - __asm mov edx, height -#else - __asm__("mov edx, %[height] " : [height] "+m" (height)); -#endif + window_scrollsize_set_registers(width, height); } /* rct2: 0x006978CC */ void window_guest_rides_scroll_mouse_down(){ int index; - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items) return; @@ -1642,10 +1636,10 @@ void window_guest_rides_scroll_mouse_down(){ /* rct2: 0x0069789C */ void window_guest_rides_scroll_mouse_over(){ int index; - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items)return; @@ -1660,6 +1654,8 @@ void window_guest_rides_scroll_mouse_over(){ void window_guest_rides_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update(w); + if (window_guest_page_widgets[w->page] != w->widgets){ w->widgets = window_guest_page_widgets[w->page]; window_init_scroll_widgets(w); @@ -1782,6 +1778,7 @@ void window_guest_finance_update(){ void window_guest_finance_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ w->widgets = window_guest_page_widgets[w->page]; @@ -1921,6 +1918,7 @@ void window_guest_thoughts_update(){ void window_guest_thoughts_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ w->widgets = window_guest_page_widgets[w->page]; @@ -2023,6 +2021,7 @@ void window_guest_inventory_update(){ void window_guest_inventory_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ w->widgets = window_guest_page_widgets[w->page]; @@ -2148,7 +2147,7 @@ void window_guest_inventory_paint(){ no_items++; RCT2_GLOBAL(0x13CE952, uint32) = 5089 + i; - RCT2_GLOBAL(0x13CE956, uint16) = 2188; + RCT2_GLOBAL(0x13CE956, uint16) = 2188 + i; RCT2_GLOBAL(0x13CE958, uint16) = RCT2_GLOBAL(0x13573D4, uint16); RCT2_GLOBAL(0x13CE95A, uint32) = RCT2_GLOBAL(0x13573D8, uint32); diff --git a/src/windows/guest_list.c b/src/windows/guest_list.c index 1d9ec23465..47fff45313 100644 --- a/src/windows/guest_list.c +++ b/src/windows/guest_list.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../interface/widget.h" #include "../interface/window.h" @@ -28,6 +29,7 @@ #include "../sprites.h" #include "../world/sprite.h" #include "dropdown.h" +#include "../interface/themes.h" enum { PAGE_INDIVIDUAL, @@ -115,13 +117,13 @@ static void* window_guest_list_events[] = { window_guest_list_scrollpaint }; -static int _window_guest_list_highlighted_index; -static int _window_guest_list_selected_tab; -static int _window_guest_list_selected_filter; -static int _window_guest_list_selected_page; -static int _window_guest_list_selected_view; -static int _window_guest_list_num_pages; -static int _window_guest_list_num_groups; +static int _window_guest_list_highlighted_index; // 0x00F1EE10 +static int _window_guest_list_selected_tab; // 0x00F1EE12 +static int _window_guest_list_selected_filter; // 0x00F1EE06 +static int _window_guest_list_selected_page; // 0x00F1EE07 +static int _window_guest_list_selected_view; // 0x00F1EE13 +static int _window_guest_list_num_pages; // 0x00F1EE08 +static int _window_guest_list_num_groups; // 0x00F1AF22 static uint16 _window_guest_list_groups_num_guests[240]; static uint32 _window_guest_list_groups_argument_1[240]; @@ -146,7 +148,7 @@ void window_guest_list_open() if (window != NULL) return; - window = window_create_auto_pos(350, 330, (uint32*)window_guest_list_events, WC_GUEST_LIST, 0x0400); + window = window_create_auto_pos(350, 330, (uint32*)window_guest_list_events, WC_GUEST_LIST, WF_10 | WF_RESIZABLE); window->widgets = window_guest_list_widgets; window->enabled_widgets = (1 << WIDX_CLOSE) | @@ -172,10 +174,91 @@ void window_guest_list_open() window->min_height = 330; window->max_width = 500; window->max_height = 450; - window->flags |= WF_RESIZABLE; - window->colours[0] = 1; - window->colours[1] = 15; - window->colours[2] = 15; +} + +/** +* type == 0 -> guests on ride +* type == 1 -> guests in queue +* type == 2 -> guests thinking about ride +* type == 3 -> guests thinking X, opened from news item +* index is number of the ride or index of the thought +* values of eax and edx probably determine the filter name string +* +* rct2: 0x006993BA +*/ +void window_guest_list_open_with_filter(int type, int index) +{ + uint32 eax, edx; + + window_guest_list_open(); + + _window_guest_list_selected_page = 0; + _window_guest_list_num_pages = 1; + + RCT2_GLOBAL(0x009AC7E0, uint8) = 0; + RCT2_GLOBAL(0x009AC7F0, uint8) = 0; + + rct_ride *ride; + if (type != 3) { // common for cases 0, 1, 2 + ride = GET_RIDE(index & 0x000000FF); + eax = ride->name; + edx = ride->name_arguments; + } + + switch(type) + { + case 0: + _window_guest_list_selected_filter = 0; + + eax = (eax << 16) + 1435; + + if ((RCT2_GLOBAL(0x97CF40 + ride->type * 8, uint32) & 0x400000) != 0) + eax++; + + RCT2_GLOBAL(0x00F1EDF6, uint32) = eax; + RCT2_GLOBAL(0x00F1EDFA, uint32) = edx; + + _window_guest_list_highlighted_index = 0xFFFF; + _window_guest_list_selected_tab = 0; + _window_guest_list_selected_view = 0; + break; + case 1: + _window_guest_list_selected_filter = 0; + + eax = (eax << 16) + 1433; + + RCT2_GLOBAL(0x00F1EDF6, uint32) = eax; + RCT2_GLOBAL(0x00F1EDFA, uint32) = edx; + + _window_guest_list_highlighted_index = 0xFFFF; + _window_guest_list_selected_tab = 0; + _window_guest_list_selected_view = 0; + break; + case 2: + _window_guest_list_selected_filter = 1; + + eax = (eax << 16) + 0xFFFF; + + RCT2_GLOBAL(0x00F1EDF6, uint32) = eax; + RCT2_GLOBAL(0x00F1EDFA, uint32) = edx; + + _window_guest_list_highlighted_index = 0xFFFF; + _window_guest_list_selected_tab = 0; + _window_guest_list_selected_view = 1; + break; + case 3: + _window_guest_list_selected_filter = 1; + + index = (index & 0x000000FF) + 1480; + + RCT2_GLOBAL(0x00F1EDF6, uint32) = index; + RCT2_GLOBAL(0x00F1EDFA, uint32) = 0; + + _window_guest_list_highlighted_index = 0xFFFF; + _window_guest_list_selected_tab = 0; + _window_guest_list_selected_view = 1; + break; + } } /** @@ -252,7 +335,7 @@ static void window_guest_list_mousedown(int widgetIndex, rct_window*w, rct_widge w->y + widget->top, widget->bottom - widget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, _window_guest_list_num_pages, widget->right - widget->left - 3 ); @@ -276,7 +359,7 @@ static void window_guest_list_mousedown(int widgetIndex, rct_window*w, rct_widge w->y + widget->top, widget->bottom - widget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, 2, widget->right - widget->left - 3 ); @@ -333,7 +416,7 @@ static void window_guest_list_update(rct_window *w) */ static void window_guest_list_scrollgetsize() { - int i, y, numGuests, spriteIndex; + int i, y, numGuests, spriteIndex, width, height; rct_window *w; rct_peep *peep; @@ -384,18 +467,10 @@ static void window_guest_list_scrollgetsize() window_invalidate(w); } - #ifdef _MSC_VER - __asm mov ecx, 447 - #else - __asm__ ( "mov ecx, 447 " ); - #endif - - #ifdef _MSC_VER - __asm mov edx, y - #else - __asm__ ( "mov edx, %[y] " : [y] "+m" (y) ); - #endif + width = 447; + height = y; + window_scrollsize_set_registers(width, height); } /** @@ -405,11 +480,11 @@ static void window_guest_list_scrollgetsize() static void window_guest_list_scrollmousedown() { int i, spriteIndex; - short x, y; + short x, y, scrollIndex; rct_window *w; rct_peep *peep; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); switch (_window_guest_list_selected_tab) { case PAGE_INDIVIDUAL: @@ -453,10 +528,10 @@ static void window_guest_list_scrollmousedown() static void window_guest_list_scrollmouseover() { int i; - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); i = y / (_window_guest_list_selected_tab == PAGE_INDIVIDUAL ? 10 : 21); i += _window_guest_list_selected_page * 3173; @@ -484,6 +559,7 @@ static void window_guest_list_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); w->pressed_widgets &= ~(1 << WIDX_TAB_1); w->pressed_widgets &= ~(1 << WIDX_TAB_2); @@ -598,7 +674,7 @@ static void window_guest_list_scrollpaint() if (_window_guest_list_selected_filter != -1) { if (window_guest_list_is_peep_in_filter(peep)) continue; - RCT2_GLOBAL(0x009AC861, uint16) |= 1; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 0); peep->var_0C |= 0x200; } @@ -719,7 +795,7 @@ static int window_guest_list_is_peep_in_filter(rct_peep* peep) _window_guest_list_selected_view = temp; - if (((RCT2_GLOBAL(0x00F1EDF6, uint32) >> 16) & 0xFFFF) == 0xFFFF && _window_guest_list_selected_filter == 1) + if (RCT2_GLOBAL(0x00F1EDF6, uint16) == 0xFFFF && _window_guest_list_selected_filter == 1) argument1 |= 0xFFFF; if (argument1 == RCT2_GLOBAL(0x00F1EDF6, uint32) && argument2 == RCT2_GLOBAL(0x00F1EDFA, uint32)) @@ -869,4 +945,4 @@ static void window_guest_list_find_groups() nextPeep: ; } -} \ No newline at end of file +} diff --git a/src/windows/install_track.c b/src/windows/install_track.c new file mode 100644 index 0000000000..c98aca69d0 --- /dev/null +++ b/src/windows/install_track.c @@ -0,0 +1,492 @@ +/***************************************************************************** +* 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 . +*****************************************************************************/ + +#include "../addresses.h" +#include "../audio/audio.h" +#include "../editor.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../ride/ride.h" +#include "../ride/track.h" +#include "../sprites.h" +#include "error.h" +#include "../interface/themes.h" + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_TRACK_PREVIEW, + WIDX_ROTATE, + WIDX_TOGGLE_SCENERY, + WIDX_INSTALL, + WIDX_CANCEL +}; + +static rct_widget window_install_track_widgets[] = { + { WWT_FRAME, 0, 0, 401, 0, 399, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 400, 1, 14, 2309, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 389, 399, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_FLATBTN, 0, 15, 386, 18, 236, 0xFFFFFFFF, STR_NONE }, + { WWT_FLATBTN, 0, 376, 399, 374, 397, 5169, STR_ROTATE_90_TIP }, + { WWT_FLATBTN, 0, 376, 399, 350, 373, 5171, STR_TOGGLE_SCENERY_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 303, 397, 241, 252, 3378, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 0, 303, 397, 256, 267, 3379, STR_NONE }, + { WIDGETS_END }, +}; + +static void window_install_track_emptysub() { } +static void window_install_track_close(); +static void window_install_track_mouseup(); +static void window_install_track_invalidate(); +static void window_install_track_paint(); +static void window_install_track_text_input(); + +static void* window_install_track_events[] = { + (uint32*)window_install_track_close, + (uint32*)window_install_track_mouseup, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_text_input, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_emptysub, + (uint32*)window_install_track_invalidate, + (uint32*)window_install_track_paint, + (uint32*)window_install_track_emptysub +}; + +ride_list_item _window_install_track_item; + +char track_dest_name[MAX_PATH]; +char track_path[MAX_PATH]; + +/** +* +* rct2: 0x006D386D +*/ +void window_install_track_open(const char* path) +{ + rct_window *w; + int x, y; + void *mem; + + window_close_by_class(WC_EDITOR_OBJECT_SELECTION); + + window_close_construction_windows(); + ride_list_item item = { + .type = 0xFF, + .entry_index = 0 + }; + _window_install_track_item = item; + + mem = malloc(1285292); + if (mem == NULL) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*) = mem; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = 2; + reset_track_list_cache(); + + x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 201; + y = max(28, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 200); + + w = window_create(x, y, 402, 400, (uint32*)window_install_track_events, WC_INSTALL_TRACK, 0); + w->widgets = window_install_track_widgets; + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_ROTATE) | (1 << WIDX_TOGGLE_SCENERY) | (1 << WIDX_INSTALL) | (1 << WIDX_CANCEL); + window_init_scroll_widgets(w); + w->track_list.var_482 = 0; + w->track_list.var_484 = 0; + window_push_others_right(w); + + memset(track_path, 0, MAX_PATH - 1); + strcpy(track_path, path); + + char* track_name_pointer = track_path; + while (*track_name_pointer++ != '\0'); + while (*--track_name_pointer != '\\'); + track_name_pointer++; + + strcpy(track_dest_name, track_name_pointer); + + window_invalidate(w); +} + +/** +* +* rct2: 0x006CFB82 +*/ +static void window_install_track_select(rct_window *w, int index) +{ + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); + rct_track_design *trackDesign; + + w->track_list.var_480 = index; + + sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && index == 0) { + window_close(w); + ride_construct_new(_window_install_track_item); + return; + } + + if (RCT2_GLOBAL(0x00F44153, uint8) != 0) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) = 1; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) + index--; + + trackDesignItem = trackDesignList + (index * 128); + RCT2_GLOBAL(0x00F4403C, uint8*) = trackDesignItem; + + window_track_list_format_name( + (char*)0x009BC313, + trackDesignItem, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? + 0 : + FORMAT_WHITE, + 1); + + char track_path[MAX_PATH] = { 0 }; + subsitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignItem); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + window_track_manage_open(); + return; + } + + if (!load_track_design(track_path)) { + w->track_list.var_480 = 0xFFFF; + window_invalidate(w); + return; + } + + trackDesign = track_get_info(index, NULL); + if (trackDesign == NULL) return; + if (trackDesign->track_td6.track_flags & 4) + window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1); + + window_close(w); + window_track_place_open(); +} + +/** +* +* rct2: 0x006D41DC +*/ +static void window_install_track_close() +{ + free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*)); +} + +/** +* +* rct2: 0x006D407A +*/ +static void window_install_track_mouseup() +{ + rct_window *w; + short widgetIndex, result; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + case WIDX_CANCEL: + window_close(w); + break; + case WIDX_ROTATE: + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8)++; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) %= 4; + window_invalidate(w); + break; + case WIDX_TOGGLE_SCENERY: + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) ^= 1; + reset_track_list_cache(); + window_invalidate(w); + break; + case WIDX_INSTALL: + result = install_track(track_path, track_dest_name); + + if (result == 1) + window_close(w); + else if(result == 0){ + window_error_open(3380, 3382); + window_close(w); + } + else{ + // Copy the track name into the string buffer. + window_track_list_format_name(RCT2_ADDRESS(0x009BC677, char), track_dest_name, 0, 0); + window_text_input_open(w, WIDX_INSTALL, 3383, 3384, 3165, 0, 255); + } + break; + } +} + + +/** +* +* rct2: 0x006D3B06 +*/ +static void window_install_track_invalidate() +{ + rct_window *w; + window_get_register(w); + colour_scheme_update(w); + + w->pressed_widgets |= 1 << WIDX_TRACK_PREVIEW; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) == 0) + w->pressed_widgets |= (1 << WIDX_TOGGLE_SCENERY); + else + w->pressed_widgets &= ~(1 << WIDX_TOGGLE_SCENERY); + + if (w->track_list.var_482 != 0xFFFF) { + w->disabled_widgets &= ~(1 << WIDX_TRACK_PREVIEW); + } + else { + w->disabled_widgets |= (1 << WIDX_TRACK_PREVIEW); + } +} + +/** +* +* rct2: 0x006D3B1F +*/ +static void window_install_track_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_widget *widget; + rct_track_design *trackDesign = NULL; + uint8 *image, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); + uint16 holes, speed, drops, dropHeight, inversions; + fixed32_2dp rating; + int x, y, colour, gForces, airTime; + rct_g1_element tmpElement, *subsituteElement; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + if (w->track_list.var_482 == 0xFFFF) + return; + + // Track preview + widget = &window_install_track_widgets[WIDX_TRACK_PREVIEW]; + x = w->x + widget->left + 1; + y = w->y + widget->top + 1; + colour = RCT2_GLOBAL(0x0141FC44 + (w->colours[0] * 8), uint8); + gfx_fill_rect(dpi, x, y, x + 369, y + 216, colour); + + //call 6d3993 (load track) + trackDesign = temp_track_get_info(track_path, &image); + if (trackDesign == NULL) + return; + + rct_track_td6* track_td6 = &trackDesign->track_td6; + + subsituteElement = &g1Elements[0]; + tmpElement = *subsituteElement; + subsituteElement->offset = image; + subsituteElement->width = 370; + subsituteElement->height = 217; + subsituteElement->x_offset = 0; + subsituteElement->y_offset = 0; + subsituteElement->flags = G1_FLAG_BMP; + gfx_draw_sprite(dpi, 0, x, y, 0); + *subsituteElement = tmpElement; + + x = w->x + (widget->left + widget->right) / 2; + y = w->y + widget->bottom - 12; + + RCT2_GLOBAL(0x00F44153, uint8) = 0; + + // Warnings + if (track_td6->track_flags & 1) { + RCT2_GLOBAL(0x00F44153, uint8) = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) == 0) { + // Scenery not available + gfx_draw_string_centred_clipped(dpi, STR_DESIGN_INCLUDES_SCENERY_WHICH_IS_UNAVAILABLE, NULL, 0, x, y, 368); + y -= 10; + } + } + + // Track design name + window_track_list_format_name((char*)0x009BC677, (char*)0x009E3504, FORMAT_WINDOW_COLOUR_1, 1); + gfx_draw_string_centred_clipped(dpi, 3165, NULL, 0, x, y, 368); + + // Information + x = w->x + widget->left + 1; + y = w->y + widget->bottom + 2; + // 0x006D3CF1 -- 0x006d3d71 missing + + if (track_td6->var_6C & 0x80000000) { + // Six flags logo + gfx_draw_sprite(dpi, SPR_SIX_FLAGS, w->x + widget->right - 50, y + 4, 0); + } + + // Stats + rating = track_td6->excitement * 10; + gfx_draw_string_left(dpi, STR_TRACK_LIST_EXCITEMENT_RATING, &rating, 0, x, y); + y += 10; + + rating = track_td6->intensity * 10; + gfx_draw_string_left(dpi, STR_TRACK_LIST_INTENSITY_RATING, &rating, 0, x, y); + y += 10; + + rating = track_td6->nausea * 10; + gfx_draw_string_left(dpi, STR_TRACK_LIST_NAUSEA_RATING, &rating, 0, x, y); + y += 14; + + if (track_td6->type != RIDE_TYPE_MAZE) { + if (track_td6->type == RIDE_TYPE_MINI_GOLF) { + // Holes + holes = track_td6->holes & 0x1F; + gfx_draw_string_left(dpi, STR_HOLES, &holes, 0, x, y); + y += 10; + } + else { + // Maximum speed + speed = ((track_td6->max_speed << 16) * 9) >> 18; + gfx_draw_string_left(dpi, STR_MAX_SPEED, &speed, 0, x, y); + y += 10; + + // Average speed + speed = ((track_td6->average_speed << 16) * 9) >> 18; + gfx_draw_string_left(dpi, STR_AVERAGE_SPEED, &speed, 0, x, y); + y += 10; + } + + // Ride length + RCT2_GLOBAL(0x013CE952 + 0, uint16) = 1345; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = track_td6->ride_length; + gfx_draw_string_left_clipped(dpi, STR_TRACK_LIST_RIDE_LENGTH, (void*)0x013CE952, 0, x, y, 214); + y += 10; + } + + if (ride_type_has_flag(track_td6->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) { + // Maximum positive vertical Gs + gForces = track_td6->max_positive_vertical_g * 32; + gfx_draw_string_left(dpi, STR_MAX_POSITIVE_VERTICAL_G, &gForces, 0, x, y); + y += 10; + + // Maximum negative verical Gs + gForces = track_td6->max_negative_vertical_g * 32; + gfx_draw_string_left(dpi, STR_MAX_NEGATIVE_VERTICAL_G, &gForces, 0, x, y); + y += 10; + + // Maximum lateral Gs + gForces = track_td6->max_lateral_g * 32; + gfx_draw_string_left(dpi, STR_MAX_LATERAL_G, &gForces, 0, x, y); + y += 10; + + // If .TD6 + if (track_td6->version_and_colour_scheme / 4 >= 2) { + if (track_td6->total_air_time != 0) { + // Total air time + airTime = track_td6->total_air_time * 25; + gfx_draw_string_left(dpi, STR_TOTAL_AIR_TIME, &airTime, 0, x, y); + y += 10; + } + } + } + + if (ride_type_has_flag(track_td6->type, RIDE_TYPE_FLAG_HAS_DROPS)) { + // Drops + drops = track_td6->drops & 0x3F; + gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y); + y += 10; + + // Drop height is multiplied by 0.75 + dropHeight = (track_td6->highest_drop_height + (track_td6->highest_drop_height / 2)) / 2; + gfx_draw_string_left(dpi, STR_HIGHEST_DROP_HEIGHT, &drops, 0, x, y); + y += 10; + } + + if (track_td6->type != RIDE_TYPE_MINI_GOLF) { + inversions = track_td6->inversions & 0x1F; + if (inversions != 0) { + // Inversions + gfx_draw_string_left(dpi, STR_INVERSIONS, &inversions, 0, x, y); + y += 10; + } + } + y += 4; + + if (track_td6->space_required_x != 0xFF) { + // Space required + RCT2_GLOBAL(0x013CE952 + 0, uint16) = track_td6->space_required_x; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = track_td6->space_required_y; + gfx_draw_string_left(dpi, STR_TRACK_LIST_SPACE_REQUIRED, (void*)0x013CE952, 0, x, y); + y += 10; + } + + if (track_td6->cost != 0) { + gfx_draw_string_left(dpi, STR_TRACK_LIST_COST_AROUND, &track_td6->cost, 0, x, y); + y += 14; + } +} + +/** +* +* rct2: 0x006D40A7 +*/ +static void window_install_track_text_input(){ + short widgetIndex; + rct_window *w; + char _cl; + char* text; + + window_text_input_get_registers(w, widgetIndex, _cl, text); + if (_cl == 0) + { + window_close(w); + return; + } + + if (widgetIndex == WIDX_INSTALL){ + + char* extension_pointer = track_dest_name; + while (*extension_pointer++ != '.'); + --extension_pointer; + strcat(text, extension_pointer); + strcpy(track_dest_name, text); + window_event_mouse_up_call(w, WIDX_INSTALL); + } +} \ No newline at end of file diff --git a/src/windows/land.c b/src/windows/land.c index 1d4ee86128..5c5c308f81 100644 --- a/src/windows/land.c +++ b/src/windows/land.c @@ -26,6 +26,7 @@ #include "../sprites.h" #include "../world/map.h" #include "dropdown.h" +#include "../interface/themes.h" enum WINDOW_LAND_WIDGET_IDX { WIDX_BACKGROUND, @@ -36,17 +37,19 @@ enum WINDOW_LAND_WIDGET_IDX { WIDX_INCREMENT, WIDX_FLOOR, WIDX_WALL, + WIDX_PAINTMODE, }; static rct_widget window_land_widgets[] = { { WWT_FRAME, 0, 0, 97, 0, 125, -1, STR_NONE }, // panel / background { WWT_CAPTION, 0, 1, 96, 1, 14, STR_LAND, STR_WINDOW_TITLE_TIP }, // title bar { WWT_CLOSEBOX, 0, 85, 95, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 0, 27, 70, 17, 48, 5503, STR_NONE }, // preview box - { WWT_TRNBTN, 1, 28, 43, 18, 33, 0x20000000 | SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_LAND_TIP }, // decrement size - { WWT_TRNBTN, 1, 54, 69, 32, 47, 0x20000000 | SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_LAND_TIP }, // increment size + { WWT_IMGBTN, 0, 10, 53, 17, 48, 5503, STR_NONE }, // preview box + { WWT_TRNBTN, 1, 11, 26, 18, 33, 0x20000000 | SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_LAND_TIP }, // decrement size + { WWT_TRNBTN, 1, 37, 52, 32, 47, 0x20000000 | SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_LAND_TIP }, // increment size { WWT_FLATBTN, 1, 2, 48, 75, 110, 0xFFFFFFFF, STR_CHANGE_BASE_LAND_TIP }, // floor texture { WWT_FLATBTN, 1, 49, 95, 75, 110, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP }, // wall texture + { WWT_FLATBTN, 1, 64, 87, 21, 44, 5173, 5127 }, // paint mode { WIDGETS_END }, }; @@ -58,6 +61,9 @@ static void window_land_dropdown(); static void window_land_update(rct_window *w); static void window_land_invalidate(); static void window_land_paint(); +static void window_land_textinput(); +static void window_land_inputsize(rct_window *w); + static void* window_land_events[] = { window_land_close, @@ -79,7 +85,7 @@ static void* window_land_events[] = { window_land_emptysub, window_land_emptysub, window_land_emptysub, - window_land_emptysub, + window_land_textinput, window_land_emptysub, window_land_emptysub, window_land_emptysub, @@ -130,19 +136,19 @@ void window_land_open() (1 << WIDX_DECREMENT) | (1 << WIDX_INCREMENT) | (1 << WIDX_FLOOR) | - (1 << WIDX_WALL); + (1 << WIDX_WALL) | + (1 << WIDX_PAINTMODE) | + (1 << WIDX_PREVIEW); window_init_scroll_widgets(window); window_push_others_below(window); RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = 255; + LandPaintMode = false; _selectedFloorTexture = 0; _selectedWallTexture = 0; RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) = MONEY32_UNDEFINED; RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) = MONEY32_UNDEFINED; - window->colours[0] = 24; - window->colours[1] = 24; - window->colours[2] = 24; } /** @@ -200,6 +206,13 @@ static void window_land_mouseup() // Invalidate the window window_invalidate(w); break; + case WIDX_PAINTMODE: + LandPaintMode ^= 1; + window_invalidate(w); + break; + case WIDX_PREVIEW: + window_land_inputsize(w); + break; } } @@ -246,6 +259,9 @@ static void window_land_mousedown(int widgetIndex, rct_window*w, rct_widget* wid gAppropriateImageDropdownItemsPerRow[4] ); break; + case WIDX_PREVIEW: + window_land_inputsize(w); + break; } } @@ -297,6 +313,36 @@ static void window_land_dropdown() } } +static void window_land_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + int size; + char* end; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (widgetIndex != WIDX_PREVIEW || !result) + return; + + size = strtol(text, &end, 10); + if (*end == '\0') { + if (size < 0) size = 0; + if (size > 64) size = 64; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = size; + window_invalidate(w); + } +} + +static void window_land_inputsize(rct_window *w) +{ + ((uint16*)TextInputDescriptionArgs)[0] = 0; + ((uint16*)TextInputDescriptionArgs)[1] = 64; + window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); +} + /** * * rct2: 0x00664272 @@ -317,12 +363,15 @@ static void window_land_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); w->pressed_widgets = (1 << WIDX_PREVIEW); if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) != 255) w->pressed_widgets |= (1 << WIDX_FLOOR); if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) != 255) w->pressed_widgets |= (1 << WIDX_WALL); + if (LandPaintMode != 0) + w->pressed_widgets |= (1 << WIDX_PAINTMODE); window_land_widgets[WIDX_FLOOR].image = SPR_FLOOR_TEXTURE_GRASS + _selectedFloorTexture; window_land_widgets[WIDX_WALL].image = SPR_WALL_TEXTURE_ROCK + _selectedWallTexture; @@ -358,6 +407,7 @@ static void window_land_paint() gfx_draw_string_centred(dpi, 3165, x, y - 2, 0, (void*)0x013CE952); } + x = w->x + (window_land_widgets[WIDX_PREVIEW].left + window_land_widgets[WIDX_PREVIEW].right) / 2 + 17; y = w->y + window_land_widgets[WIDX_PREVIEW].bottom + 5; // Draw raise cost amount diff --git a/src/windows/land_rights.c b/src/windows/land_rights.c new file mode 100644 index 0000000000..9a81fc3cbb --- /dev/null +++ b/src/windows/land_rights.c @@ -0,0 +1,282 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#include "../addresses.h" +#include "../input.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../interface/viewport.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../world/map.h" +#include "../game.h" +#include "../interface/themes.h" + +const int MAX_LAND_RIGHTS_SIZE = 64; + +enum WINDOW_WATER_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PREVIEW, + WIDX_DECREMENT, + WIDX_INCREMENT, + WIDX_BUY_LAND_RIGHTS, + WIDX_BUY_CONSTRUCTION_RIGHTS +}; + +static rct_widget window_land_rights_widgets[] = { + { WWT_FRAME, 0, 0, 97, 0, 93, -1, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 96, 1, 14, 5136, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 85, 95, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_IMGBTN, 0, 27, 70, 17, 48, SPR_LAND_TOOL_SIZE_0, STR_NONE }, // preview box + { WWT_TRNBTN, 2, 28, 43, 18, 33, 0x20000000 | SPR_LAND_TOOL_DECREASE, 5133 }, // decrement size + { WWT_TRNBTN, 2, 54, 69, 32, 47, 0x20000000 | SPR_LAND_TOOL_INCREASE, 5134 }, // increment size + { WWT_FLATBTN, 2, 22, 45, 53, 76, 0x20000000 | SPR_BUY_LAND_RIGHTS, SPR_BUY_LAND_RIGHTS_TIP }, // land rights + { WWT_FLATBTN, 2, 52, 75, 53, 76, 0x20000000 | SPR_BUY_CONSTRUCTION_RIGHTS, SPR_BUY_CONSTRUCTION_RIGHTS_TIP }, // construction rights + { WIDGETS_END }, +}; + +static int window_land_rights_should_close(); + +static void window_land_rights_emptysub() { } +static void window_land_rights_close(); +static void window_land_rights_mouseup(); +static void window_land_rights_update(); +static void window_land_rights_invalidate(); +static void window_land_rights_paint(); +static void window_land_rights_textinput(); +static void window_land_rights_inputsize(rct_window *w); + +static void* window_land_rights_events[] = { + window_land_rights_close, + window_land_rights_mouseup, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_update, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_textinput, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_emptysub, + window_land_rights_invalidate, + window_land_rights_paint, + window_land_rights_emptysub +}; + +void window_land_rights_open() +{ + rct_window* window; + + // Check if window is already open + if (window_find_by_class(WC_LAND_RIGHTS) != NULL) + return; + + window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 98, 29, 98, 94, (uint32*)window_land_rights_events, WC_LAND_RIGHTS, 0); + window->widgets = window_land_rights_widgets; + window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_DECREMENT) | (1 << WIDX_INCREMENT) | (1 << WIDX_PREVIEW) | + (1 << WIDX_BUY_LAND_RIGHTS) | (1 << WIDX_BUY_CONSTRUCTION_RIGHTS); + window_init_scroll_widgets(window); + window_push_others_below(window); + + LandRightsMode = true; + window->pressed_widgets = (1 << WIDX_BUY_LAND_RIGHTS); + + RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, uint32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, uint32) = MONEY32_UNDEFINED; + + show_land_rights(); +} + +static void window_land_rights_close() +{ + //if (LandRightsMode) + // hide_land_rights(); + //else + // hide_construction_rights(); + // If the tool wasn't changed, turn tool off + if (!window_land_rights_should_close()) + tool_cancel(); +} + +static void window_land_rights_mouseup() +{ + rct_window *w; + int limit; + short widgetIndex; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_DECREMENT: + // Decrement land tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)--; + limit = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) < limit) + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = limit; + + // Invalidate the window + window_invalidate(w); + break; + case WIDX_INCREMENT: + // Increment land tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)++; + + limit = MAX_LAND_RIGHTS_SIZE; + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > limit) + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = limit; + + // Invalidate the window + window_invalidate(w); + break; + case WIDX_PREVIEW: + window_land_rights_inputsize(w); + break; + case WIDX_BUY_LAND_RIGHTS: + if (!LandRightsMode) { + LandRightsMode = true; + hide_construction_rights(); + show_land_rights(); + window_invalidate(w); + } + break; + case WIDX_BUY_CONSTRUCTION_RIGHTS: + if (LandRightsMode) { + LandRightsMode = false; + hide_land_rights(); + show_construction_rights(); + window_invalidate(w); + } + break; + } +} + +static void window_land_rights_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + int size; + char* end; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (widgetIndex != WIDX_PREVIEW || !result) + return; + + size = strtol(text, &end, 10); + if (*end == '\0') { + if (size < 1) size = 1; + if (size > MAX_LAND_RIGHTS_SIZE) size = MAX_LAND_RIGHTS_SIZE; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = size; + window_invalidate(w); + } +} + +static void window_land_rights_inputsize(rct_window *w) +{ + ((uint16*)TextInputDescriptionArgs)[0] = 1; + ((uint16*)TextInputDescriptionArgs)[1] = MAX_LAND_RIGHTS_SIZE; + window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); +} + +static void window_land_rights_update(rct_window *w) +{ + // Close window if another tool is open + if (window_land_rights_should_close()) + window_close(w); +} + +static void window_land_rights_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); + + // Set the preview image button to be pressed down + w->pressed_widgets |= (1 << WIDX_PREVIEW) | (1 << (LandRightsMode ? WIDX_BUY_LAND_RIGHTS : WIDX_BUY_CONSTRUCTION_RIGHTS)); + w->pressed_widgets &= ~(1 << (!LandRightsMode ? WIDX_BUY_LAND_RIGHTS : WIDX_BUY_CONSTRUCTION_RIGHTS)); + + // Update the preview image + window_land_rights_widgets[WIDX_PREVIEW].image = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) <= 7 ? + SPR_LAND_TOOL_SIZE_0 + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) : + 0xFFFFFFFF; +} + +static void window_land_rights_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + int x, y; + + window_paint_get_registers(w, dpi); + + x = w->x + (window_land_rights_widgets[WIDX_PREVIEW].left + window_land_rights_widgets[WIDX_PREVIEW].right) / 2; + y = w->y + (window_land_rights_widgets[WIDX_PREVIEW].top + window_land_rights_widgets[WIDX_PREVIEW].bottom) / 2; + + window_draw_widgets(w, dpi); + // FEATURE larger land tool size support + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > 7) { + RCT2_GLOBAL(0x009BC677, char) = FORMAT_BLACK; + RCT2_GLOBAL(0x009BC678, char) = FORMAT_COMMA16; + RCT2_GLOBAL(0x009BC679, char) = 0; + RCT2_GLOBAL(0x013CE952, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + gfx_draw_string_centred(dpi, 3165, x, y - 2, 0, (void*)0x013CE952); + } + y = w->y + window_land_rights_widgets[WIDX_PREVIEW].bottom + 5; + + // Draw cost amount + x = (window_land_rights_widgets[WIDX_PREVIEW].left + window_land_rights_widgets[WIDX_PREVIEW].right) / 2 + w->x; + y = window_land_rights_widgets[WIDX_PREVIEW].bottom + w->y + 32; + if (RCT2_GLOBAL(0x00F1AD62, uint32) != MONEY32_UNDEFINED && RCT2_GLOBAL(0x00F1AD62, uint32) != 0) + gfx_draw_string_centred(dpi, 986, x, y, 0, (void*)0x00F1AD62); +} + +static int window_land_rights_should_close() +{ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + return 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_PARK_INFORMATION) + return 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) != 14) + return 1; + return 0; +} diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c new file mode 100644 index 0000000000..63228e7153 --- /dev/null +++ b/src/windows/loadsave.c @@ -0,0 +1,803 @@ +/***************************************************************************** +* 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 . +*****************************************************************************/ + +#include "../addresses.h" +#include "../config.h" +#include "../game.h" +#include "../editor.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../scenario.h" +#include "../title.h" +#include "../windows/error.h" +#include "../interface/themes.h" +#include "../util/util.h" + +#pragma region Widgets + +#define WW 340 +#define WH 400 + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_SCROLL, + WIDX_BROWSE, +}; + +// 0x9DE48C +static rct_widget window_loadsave_widgets[] = { + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_NONE, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_SCROLL, 0, 4, WW - 5, 36, WH - 40, 2, STR_NONE }, + { WWT_CLOSEBOX, 0, 4, 200, WH - 36, WH - 18, 2707, STR_NONE }, // Use native browser + { WIDGETS_END } +}; + +#pragma endregion + +#pragma region Events + +void window_loadsave_emptysub() { } +static void window_loadsave_close(); +static void window_loadsave_mouseup(); +static void window_loadsave_update(rct_window *w); +static void window_loadsave_scrollgetsize(); +static void window_loadsave_scrollmousedown(); +static void window_loadsave_scrollmouseover(); +static void window_loadsave_textinput(); +static void window_loadsave_tooltip(); +static void window_loadsave_invalidate(); +static void window_loadsave_paint(); +static void window_loadsave_scrollpaint(); + +static void* window_loadsave_events[] = { + window_loadsave_close, + window_loadsave_mouseup, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_update, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_scrollgetsize, + window_loadsave_scrollmousedown, + window_loadsave_emptysub, + window_loadsave_scrollmouseover, + window_loadsave_textinput, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_tooltip, + window_loadsave_emptysub, + window_loadsave_emptysub, + window_loadsave_invalidate, + window_loadsave_paint, + window_loadsave_scrollpaint +}; + +#pragma endregion + +typedef struct { + char name[256]; + char path[MAX_PATH]; +} loadsave_list_item; + +int _listItemsCount = 0; +loadsave_list_item *_listItems = NULL; +char _directory[MAX_PATH]; +char _extension[32]; +char *_defaultName = NULL; +int _loadsaveType; +int _type; + +static void window_loadsave_populate_list(int includeNewItem, bool browsable, const char *directory, const char *extension); +static void window_loadsave_select(rct_window *w, const char *path); + +static int has_extension(char *path, char *extension); + +static rct_window *window_overwrite_prompt_open(const char *name, const char *path); + +rct_window *window_loadsave_open(int type, char *defaultName) +{ + char path[MAX_PATH], *ch; + int includeNewItem; + rct_window* w; + _type = type; + _defaultName = defaultName; + + w = window_bring_to_front_by_class(WC_LOADSAVE); + if (w == NULL) { + w = window_create_centred(WW, WH, (uint32*)window_loadsave_events, WC_LOADSAVE, WF_STICK_TO_FRONT); + w->widgets = window_loadsave_widgets; + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_BROWSE); + w->colours[0] = 7; + w->colours[1] = 7; + w->colours[2] = 7; + } + + _loadsaveType = type; + switch (type) { + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME): + w->widgets[WIDX_TITLE].image = STR_LOAD_GAME; + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : + w->widgets[WIDX_TITLE].image = STR_SAVE_GAME; + break; + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : + w->widgets[WIDX_TITLE].image = STR_LOAD_LANDSCAPE; + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : + w->widgets[WIDX_TITLE].image = STR_SAVE_LANDSCAPE; + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : + w->widgets[WIDX_TITLE].image = STR_SAVE_SCENARIO; + break; + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : + w->widgets[WIDX_TITLE].image = 1039; + break; + } + + w->no_list_items = 0; + w->selected_list_item = -1; + + includeNewItem = (type & 1) == LOADSAVETYPE_SAVE; + switch (type & 6) { + case LOADSAVETYPE_GAME: + platform_get_user_directory(path, "save"); + if (!platform_ensure_directory_exists(path)) { + log_error("Unable to create save directory."); + window_close(w); + return NULL; + } + + window_loadsave_populate_list(includeNewItem, TRUE, path, ".sv6"); + break; + case LOADSAVETYPE_LANDSCAPE: + platform_get_user_directory(path, "landscape"); + if (!platform_ensure_directory_exists(path)) { + log_error("Unable to create landscapes directory."); + window_close(w); + return NULL; + } + + window_loadsave_populate_list(includeNewItem, TRUE, path, ".sc6"); + break; + case LOADSAVETYPE_SCENARIO: + /* + Uncomment when user scenarios are separated + + platform_get_user_directory(path, "scenario"); + if (!platform_ensure_directory_exists(path)) { + log_error("Unable to create scenarios directory."); + window_close(w); + return NULL; + } + */ + + strcpy(path, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char)); + ch = strchr(path, '*'); + if (ch != NULL) + *ch = 0; + + window_loadsave_populate_list(includeNewItem, TRUE, path, ".sc6"); + break; + case LOADSAVETYPE_TRACK: + /* + Uncomment when user tracks are separated + + platform_get_user_directory(path, "tracks"); + if (!platform_ensure_directory_exists(path)) { + log_error("Unable to create tracks directory."); + window_close(w); + return NULL; + } + */ + + strcpy(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); + ch = strchr(path, '*'); + if (ch != NULL) + *ch = 0; + + window_loadsave_populate_list(includeNewItem, TRUE, path, ".td?"); + break; + } + w->no_list_items = _listItemsCount; + window_init_scroll_widgets(w); + return w; +} + +static void window_loadsave_close() +{ + if (_listItems != NULL) { + free(_listItems); + _listItems = NULL; + } + + window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT); +} + +static void window_loadsave_mouseup() +{ + rct_window *w; + short widgetIndex; + int result; + char filename[MAX_PATH], filter[MAX_PATH]; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex){ + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_BROWSE: + strcpy(filename, _directory); + if (_type & LOADSAVETYPE_SAVE) + strcat(filename, (char*)RCT2_ADDRESS_SCENARIO_NAME); + + memset(filter, '\0', MAX_PATH); + strncpy(filter, "*", MAX_PATH); + strncat(filter, _extension, MAX_PATH); + + switch (_type) { + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : + result = platform_open_common_file_dialog(1, (char*)language_get_string(STR_LOAD_GAME), filename, filter, _extension); + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : + result = platform_open_common_file_dialog(0, (char*)language_get_string(STR_SAVE_GAME), filename, filter, _extension); + break; + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : + result = platform_open_common_file_dialog(1, (char*)language_get_string(STR_LOAD_LANDSCAPE), filename, filter, _extension); + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : + result = platform_open_common_file_dialog(0, (char*)language_get_string(STR_SAVE_LANDSCAPE), filename, filter, _extension); + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : + result = platform_open_common_file_dialog(0, (char*)language_get_string(STR_SAVE_SCENARIO), filename, filter, _extension); + break; + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : + result = platform_open_common_file_dialog(1, (char*)language_get_string(1039), filename, filter, _extension); + break; + } + + if (result) { + if (!has_extension(filename, _extension)) { + strncat(filename, _extension, MAX_PATH); + } + window_loadsave_select(w, filename); + } + break; + } +} + +static int has_extension(char *path, char *extension) +{ + int extensionLength = strlen(extension); + int pathLength = strlen(path); + for (int u = 0; u < extensionLength; u++) { + if (tolower(path[pathLength - extensionLength + u]) != tolower(extension[u])) + return 0; + } + return 1; +} + +static void window_loadsave_update(rct_window *w) +{ + +} + +static void window_loadsave_scrollgetsize() +{ + rct_window *w; + int width, height; + + window_get_register(w); + + width = 0; + height = w->no_list_items * 10; + + window_scrollsize_set_registers(width, height); +} + +static void window_loadsave_scrollmousedown() +{ + int selectedItem; + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + selectedItem = y / 10; + if (selectedItem >= w->no_list_items) + return; + + // Load or overwrite + if (_listItems[selectedItem].path[0] == 0) { + rct_string_id templateStringId = 3165; + char *templateString; + + templateString = (char*)language_get_string(templateStringId); + strcpy(templateString, _defaultName); + + window_text_input_open(w, WIDX_SCROLL, STR_NONE, 2710, templateStringId, 0, 64); + } else { + if (_listItems[selectedItem].path[strlen(_listItems[selectedItem].path) - 1] == platform_get_path_separator()){ + // The selected item is a folder + int includeNewItem; + + w->no_list_items = 0; + w->selected_list_item = -1; + + includeNewItem = (_type & 1) == LOADSAVETYPE_SAVE; + + char directory[MAX_PATH]; + strncpy(directory, _listItems[selectedItem].path, sizeof(directory)); + + window_loadsave_populate_list(includeNewItem, TRUE, directory, _extension); + window_init_scroll_widgets(w); + + w->no_list_items = _listItemsCount; + } else { + if ((_loadsaveType & 1) == LOADSAVETYPE_SAVE) + window_overwrite_prompt_open(_listItems[selectedItem].name, _listItems[selectedItem].path); + else + window_loadsave_select(w, _listItems[selectedItem].path); + } + } +} + +static void window_loadsave_scrollmouseover() +{ + int selectedItem; + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + selectedItem = y / 10; + if (selectedItem >= w->no_list_items) + return; + + w->selected_list_item = selectedItem; + + window_invalidate(w); +} + +static void window_loadsave_textinput() +{ + rct_window *w; + short widgetIndex; + uint8 result; + char *text, path[MAX_PATH]; + int i, overwrite; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (!result || text[0] == 0) + return; + + strncpy(path, _directory, sizeof(path)); + strncat(path, text, sizeof(path)); + strncat(path, _extension, sizeof(path)); + + overwrite = 0; + for (i = 0; i < _listItemsCount; i++) { + if (_stricmp(_listItems[i].path, path) == 0) { + overwrite = 1; + break; + } + } + + if (overwrite) + window_overwrite_prompt_open(text, path); + else + window_loadsave_select(w, path); +} + +static void window_loadsave_tooltip() +{ + RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; +} + +static void window_loadsave_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + +static void window_loadsave_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + char buffer[256]; + // Format text + sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, _directory); + // Draw shadow + gfx_draw_string(dpi, buffer, 0, w->x + 4, w->y + 20); + +} + +static void window_loadsave_scrollpaint() +{ + int i, y; + rct_window *w; + rct_drawpixelinfo *dpi; + rct_string_id stringId, templateStringId = 3165; + char *templateString; + + window_paint_get_registers(w, dpi); + + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, RCT2_ADDRESS(0x0141FC48,uint8)[w->colours[1] * 8]); + + templateString = (char*)language_get_string(templateStringId); + for (i = 0; i < w->no_list_items; i++) { + y = i * 10; + if (y > dpi->y + dpi->height) + break; + + if (y + 10 < dpi->y) + continue; + + stringId = STR_BLACK_STRING; + if (i == w->selected_list_item) { + stringId = STR_WINDOW_COLOUR_2_STRING; + gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031); + } + + strcpy(templateString, _listItems[i].name); + gfx_draw_string_left(dpi, stringId, &templateStringId, 0, 0, y - 1); + } +} + +static int list_item_sort(const void *a, const void *b) +{ + const loadsave_list_item *itemA = (loadsave_list_item*)a; + const loadsave_list_item *itemB = (loadsave_list_item*)b; + + return strcmp(itemA->name, itemB->name); +} + +static void window_loadsave_sort_list(int index, int endIndex) +{ + int count = endIndex - index + 1; + if (count < 0) + return; + + qsort(_listItems + index, count, sizeof(loadsave_list_item), list_item_sort); +} + +static void window_loadsave_populate_list(int includeNewItem, bool browsable, const char *directory, const char *extension) +{ + int i, listItemCapacity, fileEnumHandle; + file_info fileInfo; + loadsave_list_item *listItem; + const char *src; + char *dst, filter[MAX_PATH], subDir[MAX_PATH]; + + strncpy(_directory, directory, sizeof(_directory)); + strncpy(_extension, extension, sizeof(_extension)); + + strncpy(filter, directory, sizeof(filter)); + strncat(filter, "*", sizeof(filter)); + strncat(filter, extension, sizeof(filter)); + + if (_listItems != NULL) + free(_listItems); + + listItemCapacity = 8; + _listItems = (loadsave_list_item*)malloc(listItemCapacity * sizeof(loadsave_list_item)); + _listItemsCount = 0; + + if (browsable) { + int directoryLength = strlen(directory); + int topLevel = 1; + int lastSlash = directoryLength; + for (int index = directoryLength; index >= 0; index--) { + if (directory[index] == platform_get_path_separator()) { + if (lastSlash != directoryLength){ + // The last slash has been changed before, we're now one up + lastSlash = index; + topLevel = 0; + break; + } else { + // The last slash, after the whole path + lastSlash = index; + } + } + } + if (!topLevel){ + listItem = &_listItems[_listItemsCount]; + strncpy(listItem->name, language_get_string(2718), sizeof(listItem->name)); + memset(listItem->path, '\0', MAX_PATH); + strncpy(listItem->path, directory, lastSlash + 1); + _listItemsCount++; + } + } + + if (includeNewItem) { + listItem = &_listItems[_listItemsCount]; + strncpy(listItem->name, language_get_string(2719), sizeof(listItem->name)); + listItem->path[0] = 0; + _listItemsCount++; + } + + int sortStartIndex = _listItemsCount; + fileEnumHandle = platform_enumerate_directories_begin(directory); + while (platform_enumerate_directories_next(fileEnumHandle, subDir)){ + if (listItemCapacity <= _listItemsCount) { + listItemCapacity *= 2; + _listItems = realloc(_listItems, listItemCapacity * sizeof(loadsave_list_item)); + } + + listItem = &_listItems[_listItemsCount]; + memset(listItem->path, '\0', MAX_PATH); + strncpy(listItem->path, directory, MAX_PATH); + strncat(listItem->path, subDir, MAX_PATH); + strncpy(listItem->name, subDir, sizeof(listItem->name)); + + _listItemsCount++; + } + platform_enumerate_files_end(fileEnumHandle); + window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1); + + sortStartIndex = _listItemsCount; + fileEnumHandle = platform_enumerate_files_begin(filter); + while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + if (listItemCapacity <= _listItemsCount) { + listItemCapacity *= 2; + _listItems = realloc(_listItems, listItemCapacity * sizeof(loadsave_list_item)); + } + + listItem = &_listItems[_listItemsCount]; + strncpy(listItem->path, directory, sizeof(listItem->path)); + strncat(listItem->path, fileInfo.path, sizeof(listItem->path)); + + src = fileInfo.path; + dst = listItem->name; + i = 0; + while (*src != 0 && *src != '.' && i < sizeof(listItem->name) - 1) { + *dst++ = *src++; + i++; + } + *dst = 0; + + _listItemsCount++; + } + platform_enumerate_files_end(fileEnumHandle); + window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1); +} + +static void window_loadsave_select(rct_window *w, const char *path) +{ + switch (_loadsaveType) { + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : + if (game_load_save(path)) { + window_close(w); + gfx_invalidate_screen(); + rct2_endupdate(); + } + else { + // 1050, not the best message... + window_error_open(STR_LOAD_GAME, 1050); + } + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : + if (scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 1 : 0)) { + window_close(w); + + game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); + gfx_invalidate_screen(); + } + else { + window_error_open(STR_SAVE_GAME, 1047); + } + break; + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : + editor_load_landscape(path); + if (1) { + gfx_invalidate_screen(); + rct2_endupdate(); + } + else { + // 1050, not the best message... + window_error_open(STR_LOAD_LANDSCAPE, 1050); + } + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : + if (scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 3 : 2)) { + window_close(w); + gfx_invalidate_screen(); + } + else { + window_error_open(STR_SAVE_LANDSCAPE, 1049); + } + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : + { + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + int parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18; + s6Info->var_000 = 255; + int success = scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 3 : 2); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; + + if (success) { + window_close(w); + title_load(); + } + else { + window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED); + s6Info->var_000 = 4; + } + } + break; + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : + window_install_track_open(path); + window_close_by_class(WC_LOADSAVE); + break; + } +} + +#pragma region Overwrite prompt + +#define OVERWRITE_WW 200 +#define OVERWRITE_WH 100 + +enum { + WIDX_OVERWRITE_BACKGROUND, + WIDX_OVERWRITE_TITLE, + WIDX_OVERWRITE_CLOSE, + WIDX_OVERWRITE_OVERWRITE, + WIDX_OVERWRITE_CANCEL +}; + +static rct_widget window_overwrite_prompt_widgets[] = { + { WWT_FRAME, 0, 0, OVERWRITE_WW - 1, 0, OVERWRITE_WH - 1, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, OVERWRITE_WW - 2, 1, 14, 2709, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, OVERWRITE_WW - 13, OVERWRITE_WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 10, 94, OVERWRITE_WH - 20, OVERWRITE_WH - 9, 2709, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 0, OVERWRITE_WW - 95, OVERWRITE_WW - 11, OVERWRITE_WH - 20, OVERWRITE_WH - 9, STR_SAVE_PROMPT_CANCEL, STR_NONE }, + { WIDGETS_END } +}; + +static void window_overwrite_prompt_emptysub(){} +static void window_overwrite_prompt_mouseup(); +static void window_overwrite_prompt_invalidate(); +static void window_overwrite_prompt_paint(); + +static void* window_overwrite_prompt_events[] = { + window_overwrite_prompt_emptysub, + window_overwrite_prompt_mouseup, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_emptysub, + window_overwrite_prompt_invalidate, + window_overwrite_prompt_paint, + window_overwrite_prompt_emptysub +}; + +static char _window_overwrite_prompt_name[256]; +static char _window_overwrite_prompt_path[MAX_PATH]; + +static rct_window *window_overwrite_prompt_open(const char *name, const char *path) +{ + rct_window *w; + + window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT); + + w = window_create_centred(OVERWRITE_WW, OVERWRITE_WH, (uint32*)window_overwrite_prompt_events, WC_LOADSAVE_OVERWRITE_PROMPT, WF_STICK_TO_FRONT); + w->widgets = window_overwrite_prompt_widgets; + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_OVERWRITE_CANCEL) | (1 << WIDX_OVERWRITE_OVERWRITE); + window_init_scroll_widgets(w); + w->flags |= WF_TRANSPARENT; + w->colours[0] = 154; + + strncpy(_window_overwrite_prompt_name, name, sizeof(_window_overwrite_prompt_name)); + strncpy(_window_overwrite_prompt_path, path, sizeof(_window_overwrite_prompt_path)); + + return w; +} + +static void window_overwrite_prompt_mouseup() +{ + short widgetIndex; + rct_window *w, *loadsaveWindow; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex){ + case WIDX_OVERWRITE_OVERWRITE: + loadsaveWindow = window_find_by_class(WC_LOADSAVE); + if (loadsaveWindow != NULL) + window_loadsave_select(loadsaveWindow, _window_overwrite_prompt_path); + window_close(w); + break; + case WIDX_OVERWRITE_CANCEL: + case WIDX_OVERWRITE_CLOSE: + window_close(w); + } +} + +static void window_overwrite_prompt_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + +static void window_overwrite_prompt_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + rct_string_id templateStringId = 3165; + char *templateString; + + templateString = (char*)language_get_string(templateStringId); + strcpy(templateString, _window_overwrite_prompt_name); + + int x = w->x + w->width / 2; + int y = w->y + (w->height / 2) - 3; + gfx_draw_string_centred_wrapped(dpi, &templateStringId, x, y, w->width - 4, 2708, 0); +} + + +#pragma endregion diff --git a/src/windows/map.c b/src/windows/map.c index 47128823da..4e8e2f9149 100644 --- a/src/windows/map.c +++ b/src/windows/map.c @@ -25,7 +25,9 @@ #include "../interface/viewport.h" #include "../interface/window.h" #include "../sprites.h" -#include "../windows/scenery.h" +#include "../world/scenery.h" +#include "../interface/themes.h" +#include "../cheats.h" enum WINDOW_MAP_WIDGET_IDX { @@ -77,8 +79,15 @@ static rct_widget window_map_widgets[] = { { WIDGETS_END }, }; +// used in transforming viewport view coordinates to minimap coordinates +// rct2: 0x00981BBC (these two tables are interspersed) +static const sint16 _minimap_offsets_x[4] = { 0xF8, 0x1F8, 0xF8, 0xFFF8 }; +// rct2: 0x00981BBE +static const sint16 _minimap_offsets_y[4] = { 0, 0x100, 0x200, 0x100 }; + static void window_map_emptysub() { } static void window_map_close(); +static void window_map_resize(); static void window_map_mouseup(); static void window_map_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); static void window_map_update(rct_window *w); @@ -88,16 +97,19 @@ static void window_map_invalidate(); static void window_map_paint(); static void window_map_scrollpaint(); static void window_map_tooltip(); +static void window_map_textinput(); +static void window_map_inputsize_land(rct_window *w); +static void window_map_inputsize_map(rct_window *w); static void window_map_set_bounds(rct_window* w); static void window_map_init_map(); -static void sub_68C990(); +static void window_map_center_on_view_point(); static void* window_map_events[] = { window_map_close, window_map_mouseup, - window_map_emptysub, + window_map_resize, window_map_mousedown, window_map_emptysub, window_map_emptysub, @@ -114,7 +126,7 @@ static void* window_map_events[] = { window_map_scrollmousedown, window_map_scrollmousedown, window_map_emptysub, - window_map_emptysub, + window_map_textinput, window_map_emptysub, window_map_emptysub, window_map_tooltip, @@ -147,14 +159,16 @@ void window_map_open() return; RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint32*) = map_image_data; - w = window_create_auto_pos(245, 259, (uint32*)window_map_events, WC_MAP, 0x0400); + w = window_create_auto_pos(245, 259, (uint32*)window_map_events, WC_MAP, WF_10); w->widgets = window_map_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_PEOPLE_TAB) | (1 << WIDX_RIDES_TAB) | + (1 << WIDX_MAP_SIZE_SPINNER) | (1 << WIDX_MAP_SIZE_SPINNER_UP) | (1 << WIDX_MAP_SIZE_SPINNER_DOWN) | + (1 << WIDX_LAND_TOOL) | (1 << WIDX_LAND_TOOL_SMALLER) | (1 << WIDX_LAND_TOOL_LARGER) | (1 << WIDX_SET_LAND_RIGHTS) | @@ -165,19 +179,16 @@ void window_map_open() (1 << WIDX_BUILD_PARK_ENTRANCE) | (1 << WIDX_ROTATE_90) | (1 << WIDX_PEOPLE_STARTING_POSITION); - w->var_020 |= 0x300; + w->hold_down_widgets = + (1 << WIDX_MAP_SIZE_SPINNER_UP) | + (1 << WIDX_MAP_SIZE_SPINNER_DOWN); window_init_scroll_widgets(w); - window_map_set_bounds(w); - w->map.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint16); window_map_init_map(); RCT2_GLOBAL(0x00F64F05, uint8) = 0; - sub_68C990(); - - w->colours[0] = 12; - w->colours[1] = 24; + window_map_center_on_view_point(); } /** @@ -193,9 +204,28 @@ static void window_map_close() rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint32*)); if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == w->classification && - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == w->number) { + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, uint16) == w->number) { tool_cancel(); } + //Reset land tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 0; +} + +/** +* +* rct2: 0x0068D7DC +*/ +void window_map_resize() +{ + rct_window *w; + + window_get_register(w); + + w->flags |= WF_RESIZABLE; // (1 << 8) + w->min_width = 245; + w->max_width = 800; + w->min_height = 259; + w->max_height = 560; } /** @@ -204,12 +234,13 @@ static void window_map_close() */ static void window_map_mouseup() { - //RCT2_CALLPROC_EBPSAFE(0x0068CFC1); sint16 var_idx; rct_window* var_w; + //Maximum land ownership tool size + int land_tool_limit; window_widget_get_registers(var_w, var_idx); - + switch (var_idx) { case WIDX_CLOSE: @@ -266,18 +297,20 @@ static void window_map_mouseup() case WIDX_LAND_TOOL_SMALLER: --RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + land_tool_limit=1; - if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) < 1) - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) < land_tool_limit) + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = land_tool_limit; window_invalidate(var_w); break; case WIDX_LAND_TOOL_LARGER: ++RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + land_tool_limit=64; - if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > 7) - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 7; + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > land_tool_limit) + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = land_tool_limit; window_invalidate(var_w); break; @@ -289,8 +322,8 @@ static void window_map_mouseup() RCT2_GLOBAL(0x9E32D2, sint8) = 0; - if (!(RCT2_GLOBAL(0x9DE518, sint32) & (1 << 6))) // Remove? - RCT2_GLOBAL(0x9DE518, sint32) |= (1 << 6); + if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, sint32) & INPUT_FLAG_6)) // Remove? + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, sint32) |= INPUT_FLAG_6; show_gridlines(); show_land_rights(); @@ -315,6 +348,12 @@ static void window_map_mouseup() show_land_rights(); show_construction_rights(); break; + case WIDX_LAND_TOOL: + window_map_inputsize_land(var_w); + break; + case WIDX_MAP_SIZE_SPINNER: + window_map_inputsize_map(var_w); + break; default: if (var_idx >= WIDX_PEOPLE_TAB && var_idx <= WIDX_RIDES_TAB) @@ -339,14 +378,74 @@ static void window_map_mouseup() */ static void window_map_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { - // The normal map window doesn't have widget 8 or 9. - // I assume these widgets refer to the Scenario Editor's map window. - if (widgetIndex == 8) { - RCT2_CALLPROC_EBPSAFE(0x0068D641); + // These widgets all refer to the Scenario Editor's map window. + if (widgetIndex == WIDX_MAP_SIZE_SPINNER_UP) { + RCT2_CALLPROC_X(0x0068D641, 0, 0, 0, widgetIndex, (int)w, 0, 0); } - else if (widgetIndex == 9) { - RCT2_CALLPROC_EBPSAFE(0x0068D6B4); + else if (widgetIndex == WIDX_MAP_SIZE_SPINNER_DOWN) { + RCT2_CALLPROC_X(0x0068D6B4, 0, 0, 0, widgetIndex, (int)w, 0, 0); } + else if (widgetIndex == WIDX_SET_LAND_RIGHTS) + { + // When unselecting the land rights tool, reset the size so the number doesn't + // stay in the map window. + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + } +} + +static void window_map_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + int size; + char* end; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (result) { + if (widgetIndex == WIDX_LAND_TOOL) { + size = strtol(text, &end, 10); + if (*end == '\0') { + if (size < 1) size = 1; + if (size > 64) size = 64; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = size; + window_invalidate(w); + } + } + else if (widgetIndex == WIDX_MAP_SIZE_SPINNER) { + size = strtol(text, &end, 10); + if (*end == '\0') { + if (size < 50) size = 50; + if (size > 256) size = 256; + int currentSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16); + while (size < currentSize) { + RCT2_CALLPROC_X(0x0068D6B4, 0, 0, 0, widgetIndex, (int)w, 0, 0); + currentSize--; + } + while (size > currentSize) { + RCT2_CALLPROC_X(0x0068D641, 0, 0, 0, widgetIndex, (int)w, 0, 0); + currentSize++; + } + window_invalidate(w); + } + } + } +} + +static void window_map_inputsize_land(rct_window *w) +{ + ((uint16*)TextInputDescriptionArgs)[0] = 1; + ((uint16*)TextInputDescriptionArgs)[1] = 64; + window_text_input_open(w, WIDX_LAND_TOOL, 5128, 5129, STR_NONE, STR_NONE, 3); +} + +static void window_map_inputsize_map(rct_window *w) +{ + ((uint16*)TextInputDescriptionArgs)[0] = 50; + ((uint16*)TextInputDescriptionArgs)[1] = 256; + window_text_input_open(w, WIDX_MAP_SIZE_SPINNER, 5130, 5131, STR_NONE, STR_NONE, 4); } /** @@ -355,7 +454,7 @@ static void window_map_mousedown(int widgetIndex, rct_window*w, rct_widget* widg */ static void window_map_update(rct_window *w) { - RCT2_CALLPROC_EBPSAFE(0x0068D7FB); + RCT2_CALLPROC_X(0x0068D7FB, 0, 0, 0, 0, (int)w, 0, 0); } /** @@ -364,15 +463,13 @@ static void window_map_update(rct_window *w) */ static void window_map_scrollgetsize() { + int width, height; + window_map_invalidate(); - #ifdef _MSC_VER - __asm mov ecx, 512 - __asm mov edx, 512 - #else - __asm__ ( "mov ecx, 512 " ); - __asm__ ( "mov edx, 512 " ); - #endif + width = 512; + height = 512; + window_scrollsize_set_registers(width, height); } /** @@ -381,7 +478,11 @@ static void window_map_scrollgetsize() */ static void window_map_scrollmousedown() { - RCT2_CALLPROC_EBPSAFE(0x0068D726); + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + RCT2_CALLPROC_X(0x0068D726, scrollIndex, 0, x, y, (int)w, 0, 0); } /** @@ -408,6 +509,7 @@ static void window_map_invalidate() int i, height; window_get_register(w); + colour_scheme_update(w); // set the pressed widgets pressed_widgets = (uint32)w->pressed_widgets; @@ -440,7 +542,8 @@ static void window_map_invalidate() w->widgets[WIDX_CLOSE].right = w->width - 2 - 11 + 10; w->widgets[WIDX_MAP].right = w->width - 4; - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR)) + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || + gSandboxMode) w->widgets[WIDX_MAP].bottom = w->height - 1 - 72; else if (w->selected_tab == 1) w->widgets[WIDX_MAP].bottom = w->height - 1 - 44; @@ -486,7 +589,8 @@ static void window_map_invalidate() - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR)) { + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || + gSandboxMode) { // scenario editor: build park entrance selected, show rotate button if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == WC_MAP && @@ -510,8 +614,8 @@ static void window_map_invalidate() w->widgets[WIDX_LAND_TOOL_LARGER].type = WWT_TRNBTN; for (i = 0; i < 4; i++) w->widgets[WIDX_LAND_OWNED_CHECKBOX + i].type = WWT_CHECKBOX; - w->widgets[WIDX_LAND_TOOL].image = SPR_LAND_TOOL_SIZE_0 + - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16); + w->widgets[WIDX_LAND_TOOL].image = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16) <= 7 ? SPR_LAND_TOOL_SIZE_0 + + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16) : 0xFFFFFFFF; } // if no tool is active: show the default scenario editor buttons } else { @@ -535,6 +639,22 @@ static void window_map_paint() window_draw_widgets(w, dpi); + x = w->x + (window_map_widgets[WIDX_LAND_TOOL].left + window_map_widgets[WIDX_LAND_TOOL].right) / 2; + y = w->y + (window_map_widgets[WIDX_LAND_TOOL].top + window_map_widgets[WIDX_LAND_TOOL].bottom) / 2; + + // FEATURE larger land tool size support + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE && + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint8) == WIDX_SET_LAND_RIGHTS && + (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > 7) && + (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == WC_MAP)) { + RCT2_GLOBAL(0x009BC677, char) = FORMAT_BLACK; + RCT2_GLOBAL(0x009BC678, char) = FORMAT_COMMA16; + RCT2_GLOBAL(0x009BC679, char) = 0; + RCT2_GLOBAL(0x013CE952, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + gfx_draw_string_centred(dpi, 3165, x, y - 2, 0, (void*)0x013CE952); + } + y = w->y + window_map_widgets[WIDX_LAND_TOOL].bottom + 5; + // guest tab image (animated) image_id = SPR_TAB_GUESTS_0; if (w->selected_tab == 0) @@ -560,7 +680,8 @@ static void window_map_paint() w->y + w->widgets[WIDX_PEOPLE_STARTING_POSITION].top + 18, 0); } - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR)) { + if (!((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) + || gSandboxMode)) { // render the map legend if (w->selected_tab != 0) { x = w->x + 4; @@ -578,8 +699,8 @@ static void window_map_paint() } } else { if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && - (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) != WC_MAP) && - (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint8) != WIDX_SET_LAND_RIGHTS)) + (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == WC_MAP) && + (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint8) == WIDX_SET_LAND_RIGHTS)) return; gfx_draw_string_left(dpi, STR_MAP_SIZE, 0, 0, w->x + 4, w->y + w->widgets[WIDX_MAP_SIZE_SPINNER].top + 1); @@ -595,14 +716,168 @@ static void window_map_tooltip() RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = 0xC55; } +/** +* +* part of window_map_paint_peep_overlay and window_map_paint_train_overlay +*/ +static void window_map_transform_to_map_coords(sint16 *left, sint16 *top) +{ + sint16 x = *left, y = *top; + sint16 temp; + + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { + case 3: + temp = x; + x = y; + y = temp; + x = 0x1FFF - x; + break; + case 2: + x = 0x1FFF - x; + y = 0x1FFF - y; + break; + case 1: + temp = x; + x = y; + y = temp; + y = 0x1FFF - y; + break; + case 0: + break; + } + x >>= 5; + y >>= 5; + + *left = -x + y + 0xF8; + *top = x + y - 8; +} + +/** +* +* rct2: 0x0068DADA +*/ +static void window_map_paint_peep_overlay(rct_drawpixelinfo *dpi) +{ + rct_peep *peep; + uint16 spriteIndex; + + sint16 left, right, bottom, top; + sint16 color; + + FOR_ALL_PEEPS(spriteIndex, peep) { + left = peep->x; + top = peep->y; + + if (left == SPRITE_LOCATION_NULL) + continue; + + window_map_transform_to_map_coords(&left, &top); + + right = left; + bottom = top; + + color = 0x14; + + if ((peep->var_0C & 0x200) != 0) { + if (peep->type == PEEP_TYPE_STAFF) { + if ((RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) & (1 << 3)) != 0) { + color = 0x8A; + left--; + if ((RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) & (1 << 15)) == 0) + color = 0xA; + } + } else { + if ((RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) & (1 << 1)) != 0) { + color = 0xAC; + left--; + if ((RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) & (1 << 15)) == 0) + color = 0x15; + } + } + } + gfx_fill_rect(dpi, left, top, right, bottom, color); + } +} + +/** +* +* rct2: 0x0068DBC1 +*/ +static void window_map_paint_train_overlay(rct_drawpixelinfo *dpi) +{ + rct_vehicle *train, *vehicle; + uint16 train_index, vehicle_index; + + sint16 left, top, right, bottom; + + for (train_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_VEHICLE, uint16); train_index != SPRITE_INDEX_NULL; train_index = train->next) { + train = GET_VEHICLE(train_index); + for (vehicle_index = train_index; vehicle_index != SPRITE_INDEX_NULL; vehicle_index = vehicle->next_vehicle_on_train) { + vehicle = GET_VEHICLE(vehicle_index); + + left = vehicle->x; + top = vehicle->y; + + if (left == SPRITE_LOCATION_NULL) + continue; + + window_map_transform_to_map_coords(&left, &top); + + right = left; + bottom = top; + + gfx_fill_rect(dpi, left, top, right, bottom, 0xAB); + } + } +} + +/** +* The call to gfx_fill_rect was originally wrapped in sub_68DABD which made sure that arguments were ordered correctly, +* but it doesn't look like it's ever necessary here so the call was removed. +* +* rct2: 0x0068D8CE +*/ +static void window_map_paint_hud_rectangle(rct_drawpixelinfo *dpi) +{ + rct_window *main_window = window_get_main(); + if (main_window == NULL) + return; + rct_viewport *viewport = main_window->viewport; + if (viewport == NULL) + return; + + int rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + sint16 offset_x = _minimap_offsets_x[rotation]; + sint16 offset_y = _minimap_offsets_y[rotation]; + + sint16 left = (viewport->view_x >> 5) + offset_x; + sint16 right = ((viewport->view_x + viewport->view_width) >> 5) + offset_x; + sint16 top = (viewport->view_y >> 4) + offset_y; + sint16 bottom = ((viewport->view_y + viewport->view_height) >> 4) + offset_y; + + // top horizontal lines + gfx_fill_rect(dpi, left, top, left + 3, top, 0x38); + gfx_fill_rect(dpi, right - 3, top, right, top, 0x38); + + // left vertical lines + gfx_fill_rect(dpi, left, top, left, top + 3, 0x38); + gfx_fill_rect(dpi, left, bottom - 3, left, bottom, 0x38); + + // bottom horizontal lines + gfx_fill_rect(dpi, left, bottom, left + 3, bottom, 0x38); + gfx_fill_rect(dpi, right - 3, bottom, right, bottom, 0x38); + + // right vertical lines + gfx_fill_rect(dpi, right, top, right, top + 3, 0x38); + gfx_fill_rect(dpi, right, bottom - 3, right, bottom, 0x38); +} + /** * * rct2: 0x0068CF23 */ static void window_map_scrollpaint() { - //RCT2_CALLPROC_EBPSAFE(0x0068CF23); - rct_window *w; rct_drawpixelinfo *dpi; rct_g1_element *g1_element, pushed_g1_element; @@ -611,7 +886,7 @@ static void window_map_scrollpaint() gfx_clear(dpi, 0x0A0A0A0A); - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); + g1_element = &g1Elements[0]; pushed_g1_element = *g1_element; g1_element->offset = RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint8*); @@ -626,11 +901,11 @@ static void window_map_scrollpaint() *g1_element = pushed_g1_element; if (w->selected_tab == 0) - RCT2_CALLPROC_EBPSAFE(0x68DADA); //draws dots representing guests + window_map_paint_peep_overlay(dpi); else - RCT2_CALLPROC_EBPSAFE(0x68DBC1); //draws dots representing trains + window_map_paint_train_overlay(dpi); - RCT2_CALLPROC_EBPSAFE(0x68D8CE); //draws the HUD rectangle on the map + window_map_paint_hud_rectangle(dpi); } /** @@ -647,7 +922,7 @@ static void window_map_init_map() * * rct2: 0x0068C990 */ -static void sub_68C990() +static void window_map_center_on_view_point() { rct_window *w = window_get_main(); rct_window *w_map; @@ -661,11 +936,17 @@ static void sub_68C990() if (w_map == NULL) return; + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + + // calculate center view point of viewport and transform it to minimap coordinates + cx = ((w->viewport->view_width >> 1) + w->viewport->view_x) >> 5; dx = ((w->viewport->view_height >> 1) + w->viewport->view_y) >> 4; - cx += RCT2_GLOBAL(0x00981BBC + (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) * 4), uint16); - dx += RCT2_GLOBAL(0x00981BBE + (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) * 4), uint16); + cx += _minimap_offsets_x[rotation]; + dx += _minimap_offsets_y[rotation]; + // calculate width and height of minimap + ax = w_map->widgets[WIDX_MAP].right - w_map->widgets[WIDX_MAP].left - 11; bx = w_map->widgets[WIDX_MAP].bottom - w_map->widgets[WIDX_MAP].top - 11; bp = ax; @@ -673,13 +954,11 @@ static void sub_68C990() ax >>= 1; bx >>= 1; - cx = (cx - ax) > 0 ? cx - ax : 0; - dx = (dx - bx) > 0 ? dx - bx : 0; + cx = max(cx - ax, 0); + dx = max(dx - bx, 0); - bp = -bp; // asm: neg bp - di = -di; - bp += w_map->scrolls[0].h_right; - di += w_map->scrolls[0].v_bottom; + bp = w_map->scrolls[0].h_right - bp; + di = w_map->scrolls[0].v_bottom - di; if (bp < 0 && (bp - cx) < 0) cx = 0; @@ -689,18 +968,5 @@ static void sub_68C990() w_map->scrolls[0].h_left = cx; w_map->scrolls[0].v_top = dx; - widget_scroll_update_thumbs(w, WIDX_MAP); + widget_scroll_update_thumbs(w_map, WIDX_MAP); } - -/** -* ref. by: window_map_scrollmousedown -* rct2: 0x0068D7DC -*/ -void window_map_set_bounds(rct_window* w) -{ - w->flags |= WF_RESIZABLE; // (1 << 8) - w->min_width = 245; - w->max_width = 800; - w->min_height = 259; - w->max_height = 560; -} \ No newline at end of file diff --git a/src/windows/mapgen.c b/src/windows/mapgen.c new file mode 100644 index 0000000000..01c48c457c --- /dev/null +++ b/src/windows/mapgen.c @@ -0,0 +1,1107 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../input.h" +#include "../interface/widget.h" +#include "../interface/viewport.h" +#include "../interface/window.h" +#include "../sprites.h" +#include "../world/mapgen.h" +#include "../world/scenery.h" +#include "dropdown.h" +#include "../interface/themes.h" + +enum { + WINDOW_MAPGEN_PAGE_BASE, + WINDOW_MAPGEN_PAGE_RANDOM, + WINDOW_MAPGEN_PAGE_SIMPLEX, + WINDOW_MAPGEN_PAGE_COUNT +}; + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PAGE_BACKGROUND, + WIDX_TAB_1, + WIDX_TAB_2, + WIDX_TAB_3, + + WIDX_GENERATE, + + WIDX_MAP_SIZE = 8, + WIDX_MAP_SIZE_UP, + WIDX_MAP_SIZE_DOWN, + WIDX_BASE_HEIGHT, + WIDX_BASE_HEIGHT_UP, + WIDX_BASE_HEIGHT_DOWN, + WIDX_WATER_LEVEL, + WIDX_WATER_LEVEL_UP, + WIDX_WATER_LEVEL_DOWN, + WIDX_FLOOR_TEXTURE, + WIDX_WALL_TEXTURE, + + WIDX_RANDOM_TERRAIN = 8, + WIDX_PLACE_TREES, + + WIDX_SIMPLEX_LABEL = 8, + WIDX_SIMPLEX_LOW, + WIDX_SIMPLEX_LOW_UP, + WIDX_SIMPLEX_LOW_DOWN, + WIDX_SIMPLEX_HIGH, + WIDX_SIMPLEX_HIGH_UP, + WIDX_SIMPLEX_HIGH_DOWN, + WIDX_SIMPLEX_BASE_FREQ, + WIDX_SIMPLEX_BASE_FREQ_UP, + WIDX_SIMPLEX_BASE_FREQ_DOWN, + WIDX_SIMPLEX_OCTAVES, + WIDX_SIMPLEX_OCTAVES_UP, + WIDX_SIMPLEX_OCTAVES_DOWN, + WIDX_SIMPLEX_MAP_SIZE, + WIDX_SIMPLEX_MAP_SIZE_UP, + WIDX_SIMPLEX_MAP_SIZE_DOWN, + WIDX_SIMPLEX_WATER_LEVEL, + WIDX_SIMPLEX_WATER_LEVEL_UP, + WIDX_SIMPLEX_WATER_LEVEL_DOWN, + WIDX_SIMPLEX_FLOOR_TEXTURE, + WIDX_SIMPLEX_WALL_TEXTURE, +}; + +#pragma region Widgets + +static rct_widget window_mapgen_base_widgets[] = { + { WWT_FRAME, 0, 0, 299, 0, 195, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 298, 1, 14, 2690, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 287, 297, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 299, 43, 195, 0xFFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_NONE }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_NONE }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_NONE }, + + { WWT_DROPDOWN_BUTTON, 1, 104, 198, 52, 63, 2694, STR_NONE }, + + { WWT_SPINNER, 1, 104, 198, 52, 63, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 53, 57, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 58, 62, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 104, 198, 70, 81, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 71, 75, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 76, 80, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 104, 198, 88, 99, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 89, 93, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 94, 98, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_FLATBTN, 1, 104, 150, 106, 141, 0xFFFFFFFF, STR_CHANGE_BASE_LAND_TIP }, + { WWT_FLATBTN, 1, 151, 197, 106, 141, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP }, + { WIDGETS_END }, +}; + +static rct_widget window_mapgen_random_widgets[] = { + { WWT_FRAME, 0, 0, 299, 0, 195, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 298, 1, 14, 2690, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 287, 297, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 299, 43, 195, 0xFFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_NONE }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_NONE }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_NONE }, + + { WWT_DROPDOWN_BUTTON, 1, 104, 198, 52, 63, 2694, STR_NONE }, + + { WWT_CHECKBOX, 1, 4, 198, 52, 63, 2695, STR_NONE }, + { WWT_CHECKBOX, 1, 4, 198, 70, 81, 2696, STR_NONE }, + { WIDGETS_END }, +}; + +static rct_widget window_mapgen_simplex_widgets[] = { + { WWT_FRAME, 0, 0, 299, 0, 195, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 298, 1, 14, 2690, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 287, 297, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 299, 43, 195, 0xFFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_NONE }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_NONE }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_NONE }, + + { WWT_DROPDOWN_BUTTON, 1, 104, 198, 52, 63, 2694, STR_NONE }, + + { WWT_12, 1, 4, 198, 52, 63, 2685, STR_NONE }, + + { WWT_SPINNER, 1, 104, 198, 70, 81, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 71, 75, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 76, 80, STR_NUMERIC_DOWN, STR_NONE }, + + { WWT_SPINNER, 1, 104, 198, 88, 99, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 89, 93, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 94, 98, STR_NUMERIC_DOWN, STR_NONE }, + + { WWT_SPINNER, 1, 104, 198, 106, 117, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 107, 111, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 112, 116, STR_NUMERIC_DOWN, STR_NONE }, + + { WWT_SPINNER, 1, 104, 198, 124, 135, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 125, 129, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 130, 134, STR_NUMERIC_DOWN, STR_NONE }, + + { WWT_SPINNER, 1, 104, 198, 148, 159, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 149, 153, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 154, 158, STR_NUMERIC_DOWN, STR_NONE }, + + { WWT_SPINNER, 1, 104, 198, 166, 177, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 167, 171, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 172, 176, STR_NUMERIC_DOWN, STR_NONE }, + + { WWT_FLATBTN, 1, 225, 271, 68, 103, 0xFFFFFFFF, STR_CHANGE_BASE_LAND_TIP }, + { WWT_FLATBTN, 1, 225, 271, 104, 139, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP }, + + { WIDGETS_END }, +}; + +const int window_mapgen_tab_animation_divisor[] = { 1, 1, 1 }; +const int window_mapgen_tab_animation_frames[] = { 1, 1, 1 }; + + +static rct_widget *window_mapgen_page_widgets[] = { + window_mapgen_base_widgets, + window_mapgen_random_widgets, + window_mapgen_simplex_widgets +}; + +#pragma endregion + +#pragma region Events + +static void window_mapgen_emptysub() { } + +static void window_mapgen_base_mouseup(); +static void window_mapgen_base_mousedown(int widgetIndex, rct_window *w, rct_widget* widget); +static void window_mapgen_base_dropdown(); +static void window_mapgen_base_update(rct_window *w); +static void window_mapgen_textinput(); +static void window_mapgen_base_invalidate(); +static void window_mapgen_base_paint(); +static void window_mapgen_random_mouseup(); +static void window_mapgen_random_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_mapgen_random_update(rct_window *w); +static void window_mapgen_random_invalidate(); +static void window_mapgen_random_paint(); +static void window_mapgen_simplex_mouseup(); +static void window_mapgen_simplex_mousedown(int widgetIndex, rct_window *w, rct_widget* widget); +static void window_mapgen_simplex_dropdown(); +static void window_mapgen_simplex_update(rct_window *w); +static void window_mapgen_simplex_invalidate(); +static void window_mapgen_simplex_paint(); + +static void* window_mapgen_base_events[] = { + window_mapgen_emptysub, + window_mapgen_base_mouseup, + window_mapgen_emptysub, + window_mapgen_base_mousedown, + window_mapgen_base_dropdown, + window_mapgen_emptysub, + window_mapgen_base_update, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_textinput, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_base_invalidate, + window_mapgen_base_paint, + window_mapgen_emptysub +}; + +static void* window_mapgen_random_events[] = { + window_mapgen_emptysub, + window_mapgen_random_mouseup, + window_mapgen_emptysub, + window_mapgen_random_mousedown, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_random_update, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_random_invalidate, + window_mapgen_random_paint, + window_mapgen_emptysub +}; + +static void* window_mapgen_simplex_events[] = { + window_mapgen_emptysub, + window_mapgen_simplex_mouseup, + window_mapgen_emptysub, + window_mapgen_simplex_mousedown, + window_mapgen_simplex_dropdown, + window_mapgen_emptysub, + window_mapgen_simplex_update, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_emptysub, + window_mapgen_simplex_invalidate, + window_mapgen_simplex_paint, + window_mapgen_emptysub +}; + +static void* window_mapgen_page_events[] = { + window_mapgen_base_events, + window_mapgen_random_events, + window_mapgen_simplex_events +}; + +#pragma endregion + +#pragma region Enabled widgets + +static uint32 window_mapgen_page_enabled_widgets[] = { + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_GENERATE) | + (1 << WIDX_MAP_SIZE) | + (1 << WIDX_MAP_SIZE_UP) | + (1 << WIDX_MAP_SIZE_DOWN) | + (1 << WIDX_BASE_HEIGHT) | + (1 << WIDX_BASE_HEIGHT_UP) | + (1 << WIDX_BASE_HEIGHT_DOWN) | + (1 << WIDX_WATER_LEVEL) | + (1 << WIDX_WATER_LEVEL_UP) | + (1 << WIDX_WATER_LEVEL_DOWN) | + (1 << WIDX_FLOOR_TEXTURE) | + (1 << WIDX_WALL_TEXTURE), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_GENERATE) | + (1 << WIDX_RANDOM_TERRAIN) | + (1 << WIDX_PLACE_TREES), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_GENERATE) | + (1 << WIDX_SIMPLEX_LABEL) | + (1 << WIDX_SIMPLEX_LOW) | + (1 << WIDX_SIMPLEX_LOW_UP) | + (1 << WIDX_SIMPLEX_LOW_DOWN) | + (1 << WIDX_SIMPLEX_HIGH) | + (1 << WIDX_SIMPLEX_HIGH_UP) | + (1 << WIDX_SIMPLEX_HIGH_DOWN) | + (1 << WIDX_SIMPLEX_BASE_FREQ) | + (1 << WIDX_SIMPLEX_BASE_FREQ_UP) | + (1 << WIDX_SIMPLEX_BASE_FREQ_DOWN) | + (1 << WIDX_SIMPLEX_OCTAVES) | + (1 << WIDX_SIMPLEX_OCTAVES_UP) | + (1 << WIDX_SIMPLEX_OCTAVES_DOWN) | + (1 << WIDX_SIMPLEX_MAP_SIZE) | + (1 << WIDX_SIMPLEX_MAP_SIZE_UP) | + (1 << WIDX_SIMPLEX_MAP_SIZE_DOWN) | + (1 << WIDX_SIMPLEX_WATER_LEVEL) | + (1 << WIDX_SIMPLEX_WATER_LEVEL_UP) | + (1 << WIDX_SIMPLEX_WATER_LEVEL_DOWN) | + (1 << WIDX_SIMPLEX_FLOOR_TEXTURE) | + (1 << WIDX_SIMPLEX_WALL_TEXTURE) +}; + +static uint32 window_mapgen_page_hold_down_widgets[] = { + (1 << WIDX_MAP_SIZE_UP) | + (1 << WIDX_MAP_SIZE_DOWN) | + (1 << WIDX_BASE_HEIGHT_UP) | + (1 << WIDX_BASE_HEIGHT_DOWN) | + (1 << WIDX_WATER_LEVEL_UP) | + (1 << WIDX_WATER_LEVEL_DOWN), + + 0, + + (1 << WIDX_SIMPLEX_LOW_UP) | + (1 << WIDX_SIMPLEX_LOW_DOWN) | + (1 << WIDX_SIMPLEX_HIGH_UP) | + (1 << WIDX_SIMPLEX_HIGH_DOWN) | + (1 << WIDX_SIMPLEX_BASE_FREQ_UP) | + (1 << WIDX_SIMPLEX_BASE_FREQ_DOWN) | + (1 << WIDX_SIMPLEX_OCTAVES_UP) | + (1 << WIDX_SIMPLEX_OCTAVES_DOWN) | + (1 << WIDX_SIMPLEX_MAP_SIZE_UP) | + (1 << WIDX_SIMPLEX_MAP_SIZE_DOWN) | + (1 << WIDX_SIMPLEX_WATER_LEVEL_UP) | + (1 << WIDX_SIMPLEX_WATER_LEVEL_DOWN) +}; + +#pragma endregion + +const int window_mapgen_tab_animation_loops[] = { 16, 16 }; + +#define MAPSIZE_MIN 16 +#define MAPSIZE_MAX 256 +#define BASESIZE_MIN 0 +#define BASESIZE_MAX 60 +#define WATERLEVEL_MIN 0 +#define WATERLEVEL_MAX 54 + +static void window_mapgen_set_page(rct_window *w, int page); +static void window_mapgen_set_pressed_tab(rct_window *w); +static void window_mapgen_anchor_border_widgets(rct_window *w); +static void window_mapgen_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); + +static char window_land_floor_texture_order[] = { + TERRAIN_SAND_DARK, TERRAIN_SAND_LIGHT, TERRAIN_DIRT, TERRAIN_GRASS_CLUMPS, TERRAIN_GRASS, + TERRAIN_ROCK, TERRAIN_SAND, TERRAIN_MARTIAN, TERRAIN_CHECKERBOARD, TERRAIN_ICE, + TERRAIN_GRID_RED, TERRAIN_GRID_YELLOW, TERRAIN_GRID_BLUE, TERRAIN_GRID_GREEN +}; + +static char window_land_wall_texture_order[] = { + TERRAIN_EDGE_ROCK, TERRAIN_EDGE_WOOD_RED, + TERRAIN_EDGE_WOOD_BLACK, TERRAIN_EDGE_ICE, + 0, 0 +}; + +static int _mapSize = 150; +static int _baseHeight = 12; +static int _waterLevel = 16; +static int _floorTexture = TERRAIN_GRASS; +static int _wallTexture = TERRAIN_EDGE_ROCK; +static int _randomTerrrain = 1; +static int _placeTrees = 1; + +static int _simplex_low = 6; +static int _simplex_high = 10; +static sint16 _simplex_base_freq = 60; +static int _simplex_octaves = 4; + +rct_window *window_mapgen_open() +{ + rct_window *w; + + w = window_bring_to_front_by_class(WC_MAPGEN); + if (w == NULL) { + w = window_create_centred( + 300, + 200, + window_mapgen_page_events[0], + WC_MAPGEN, + WF_10 + ); + w->number = 0; + w->frame_no = 0; + } + + w->page = WINDOW_MAPGEN_PAGE_BASE; + window_invalidate(w); + w->widgets = window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_BASE]; + w->enabled_widgets = window_mapgen_page_enabled_widgets[WINDOW_MAPGEN_PAGE_BASE]; + w->hold_down_widgets = window_mapgen_page_hold_down_widgets[WINDOW_MAPGEN_PAGE_BASE]; + w->event_handlers = window_mapgen_page_events[WINDOW_MAPGEN_PAGE_BASE]; + w->pressed_widgets = 0; + w->disabled_widgets = 0; + window_init_scroll_widgets(w); + + return w; +} + +#pragma region Base page + +static void window_mapgen_base_mouseup() +{ + short widgetIndex; + rct_window *w; + mapgen_settings mapgenSettings; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + window_mapgen_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_GENERATE: + mapgenSettings.mapSize = _mapSize; + mapgenSettings.height = _baseHeight + 2; + mapgenSettings.waterLevel = _waterLevel + 2; + mapgenSettings.floor = _floorTexture; + mapgenSettings.wall = _wallTexture; + + mapgen_generate_blank(&mapgenSettings); + gfx_invalidate_screen(); + break; + case WIDX_MAP_SIZE: + ((uint16*)TextInputDescriptionArgs)[0] = MAPSIZE_MIN; + ((uint16*)TextInputDescriptionArgs)[1] = MAPSIZE_MAX; + window_text_input_open(w, WIDX_MAP_SIZE, 5130, 5131, 5182, _mapSize, 4); + break; + case WIDX_BASE_HEIGHT: + ((uint16*)TextInputDescriptionArgs)[0] = (BASESIZE_MIN - 12) / 2; + ((uint16*)TextInputDescriptionArgs)[1] = (BASESIZE_MAX - 12) / 2; + window_text_input_open(w, WIDX_BASE_HEIGHT, 5183, 5184, 5182, (_baseHeight - 12) / 2, 3); + break; + case WIDX_WATER_LEVEL: + ((uint16*)TextInputDescriptionArgs)[0] = (WATERLEVEL_MIN - 12) / 2; + ((uint16*)TextInputDescriptionArgs)[1] = (WATERLEVEL_MAX - 12) / 2; + window_text_input_open(w, WIDX_WATER_LEVEL, 5185, 5186, 5182, (_waterLevel - 12) / 2, 3); + break; + } +} + +static void window_mapgen_base_mousedown(int widgetIndex, rct_window *w, rct_widget* widget) +{ + int i; + + switch (widgetIndex) { + case WIDX_MAP_SIZE_UP: + _mapSize = min(_mapSize + 1, MAPSIZE_MAX); + window_invalidate(w); + break; + case WIDX_MAP_SIZE_DOWN: + _mapSize = max(_mapSize - 1, MAPSIZE_MIN); + window_invalidate(w); + break; + case WIDX_BASE_HEIGHT_UP: + _baseHeight = min(_baseHeight + 2, BASESIZE_MAX); + window_invalidate(w); + break; + case WIDX_BASE_HEIGHT_DOWN: + _baseHeight = max(_baseHeight - 2, BASESIZE_MIN); + window_invalidate(w); + break; + case WIDX_WATER_LEVEL_UP: + _waterLevel = min(_waterLevel + 2, WATERLEVEL_MAX); + window_invalidate(w); + break; + case WIDX_WATER_LEVEL_DOWN: + _waterLevel = max(_waterLevel - 2, WATERLEVEL_MIN); + window_invalidate(w); + break; + case WIDX_FLOOR_TEXTURE: + for (i = 0; i < 14; i++) { + gDropdownItemsFormat[i] = -1; + gDropdownItemsArgs[i] = SPR_FLOOR_TEXTURE_GRASS + window_land_floor_texture_order[i]; + if (window_land_floor_texture_order[i] == _floorTexture) + RCT2_GLOBAL(0x009DEBA2, sint16) = i; + } + window_dropdown_show_image( + w->x + widget->left, w->y + widget->top, + widget->bottom - widget->top, + w->colours[2], + 0, + 14, + 47, 36, + gAppropriateImageDropdownItemsPerRow[14] + ); + break; + case WIDX_WALL_TEXTURE: + for (i = 0; i < 4; i++) { + gDropdownItemsFormat[i] = -1; + gDropdownItemsArgs[i] = SPR_WALL_TEXTURE_ROCK + window_land_wall_texture_order[i]; + if (window_land_wall_texture_order[i] == _wallTexture) + RCT2_GLOBAL(0x009DEBA2, sint16) = i; + } + window_dropdown_show_image( + w->x + widget->left, w->y + widget->top, + widget->bottom - widget->top, + w->colours[2], + 0, + 4, + 47, 36, + gAppropriateImageDropdownItemsPerRow[4] + ); + break; + } +} + +static void window_mapgen_base_dropdown() +{ + int type; + short dropdownIndex, widgetIndex; + rct_window *w; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + switch (widgetIndex) { + case WIDX_FLOOR_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + + type = (dropdownIndex == -1) ? + _floorTexture : + *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_FLOOR_TEXTURE_GRASS; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) == type) { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = 255; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = type; + _floorTexture = type; + } + window_invalidate(w); + break; + case WIDX_WALL_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + + type = (dropdownIndex == -1) ? + _wallTexture : + *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_WALL_TEXTURE_ROCK; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) == type) { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = 255; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = type; + _wallTexture = type; + } + window_invalidate(w); + break; + } +} + +static void window_mapgen_base_update(rct_window *w) +{ + // Tab animation + if (++w->frame_no >= window_mapgen_tab_animation_loops[w->page]) + w->frame_no = 0; + widget_invalidate(w, WIDX_TAB_1); +} + +static void window_mapgen_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + int value; + char* end; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (!result) { + return; + } + + value = strtol(text, &end, 10); + + if (*end != '\0') { + return; + } + + switch (widgetIndex) { + case WIDX_MAP_SIZE: + _mapSize = clamp(MAPSIZE_MIN, value, MAPSIZE_MAX); + break; + case WIDX_BASE_HEIGHT: + _baseHeight = clamp(BASESIZE_MIN, (value * 2) + 12, BASESIZE_MAX); + break; + case WIDX_WATER_LEVEL: + _waterLevel = clamp(WATERLEVEL_MIN, (value * 2) + 12, WATERLEVEL_MAX); + break; + } + + window_invalidate(w); + +} + +static void window_mapgen_base_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); + + if (w->widgets != window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_BASE]) { + w->widgets = window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_BASE]; + window_init_scroll_widgets(w); + } + + w->widgets[WIDX_FLOOR_TEXTURE].image = SPR_FLOOR_TEXTURE_GRASS + _floorTexture; + w->widgets[WIDX_WALL_TEXTURE].image = SPR_WALL_TEXTURE_ROCK + _wallTexture; + + window_mapgen_set_pressed_tab(w); + window_mapgen_anchor_border_widgets(w); +} + +static void window_mapgen_base_paint() +{ + uint16 arg; + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_mapgen_draw_tab_images(dpi, w); + + gfx_draw_string_left(dpi, STR_MAP_SIZE, 0, 0, w->x + 4, w->y + w->widgets[WIDX_MAP_SIZE].top + 1); + gfx_draw_string_left(dpi, 2691, 0, 0, w->x + 4, w->y + w->widgets[WIDX_BASE_HEIGHT].top + 1); + gfx_draw_string_left(dpi, 2692, 0, 0, w->x + 4, w->y + w->widgets[WIDX_WATER_LEVEL].top + 1); + gfx_draw_string_left(dpi, 2693, 0, 0, w->x + 4, w->y + w->widgets[WIDX_FLOOR_TEXTURE].top + 1); + + uint16 mapSizeArgs[2] = { _mapSize, _mapSize }; + gfx_draw_string_left(dpi, 839, mapSizeArgs, w->colours[1], w->x + w->widgets[WIDX_MAP_SIZE].left + 1, w->y + w->widgets[WIDX_MAP_SIZE].top + 1); + + arg = (_baseHeight - 12) / 2; + gfx_draw_string_left(dpi, 1737, &arg, w->colours[1], w->x + w->widgets[WIDX_BASE_HEIGHT].left + 1, w->y + w->widgets[WIDX_BASE_HEIGHT].top + 1); + + arg = (_waterLevel - 12) / 2; + gfx_draw_string_left(dpi, 1737, &arg, w->colours[1], w->x + w->widgets[WIDX_WATER_LEVEL].left + 1, w->y + w->widgets[WIDX_WATER_LEVEL].top + 1); +} + +#pragma endregion + +#pragma region Random page + +static void window_mapgen_random_mouseup() +{ + rct_window * w; + short widgetIndex; + mapgen_settings mapgenSettings; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + window_mapgen_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_GENERATE: + mapgenSettings.mapSize = _mapSize; + mapgenSettings.height = _baseHeight + 2; + mapgenSettings.waterLevel = _waterLevel + 2; + mapgenSettings.floor = _randomTerrrain ? -1 : _floorTexture; + mapgenSettings.wall = _randomTerrrain ? -1 : _wallTexture; + mapgenSettings.trees = _placeTrees; + + mapgenSettings.simplex_low = rand() % 4; + mapgenSettings.simplex_high = 12 + (rand() % (32 - 12)); + mapgenSettings.simplex_base_freq = 1.75f; + mapgenSettings.simplex_octaves = 6; + + mapgen_generate(&mapgenSettings); + gfx_invalidate_screen(); + break; + case WIDX_RANDOM_TERRAIN: + _randomTerrrain ^= 1; + break; + case WIDX_PLACE_TREES: + _placeTrees ^= 1; + break; + } +} + +static void window_mapgen_random_mousedown(int widgetIndex, rct_window *w, rct_widget* widget) +{ + +} + +static void window_mapgen_random_update(rct_window *w) +{ + // Tab animation + if (++w->frame_no >= window_mapgen_tab_animation_loops[w->page]) + w->frame_no = 0; + widget_invalidate(w, WIDX_TAB_2); +} + +static void window_mapgen_random_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); + + if (w->widgets != window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_RANDOM]) { + w->widgets = window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_RANDOM]; + window_init_scroll_widgets(w); + } + + w->pressed_widgets = 0; + if (_randomTerrrain) + w->pressed_widgets |= 1 << WIDX_RANDOM_TERRAIN; + if (_placeTrees) + w->pressed_widgets |= 1 << WIDX_PLACE_TREES; + + window_mapgen_set_pressed_tab(w); + window_mapgen_anchor_border_widgets(w); +} + +static void window_mapgen_random_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_mapgen_draw_tab_images(dpi, w); +} + +#pragma endregion + +#pragma region Simplex page + +static void window_mapgen_simplex_mouseup() +{ + rct_window * w; + short widgetIndex; + mapgen_settings mapgenSettings; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + window_mapgen_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_GENERATE: + mapgenSettings.mapSize = _mapSize; + + mapgenSettings.height = _baseHeight; + mapgenSettings.waterLevel = _waterLevel + 2; + mapgenSettings.floor = _floorTexture; + mapgenSettings.wall = _wallTexture; + mapgenSettings.trees = 0; + + mapgenSettings.simplex_low = _simplex_low; + mapgenSettings.simplex_high = _simplex_high; + mapgenSettings.simplex_base_freq = ((float)_simplex_base_freq) / 100.00f; + mapgenSettings.simplex_octaves = _simplex_octaves; + + mapgen_generate(&mapgenSettings); + gfx_invalidate_screen(); + break; + } +} + +static void window_mapgen_simplex_mousedown(int widgetIndex, rct_window *w, rct_widget* widget) +{ + int i; + + switch (widgetIndex) { + case WIDX_SIMPLEX_LOW_UP: + _simplex_low = min(_simplex_low + 1, 24); + window_invalidate(w); + break; + case WIDX_SIMPLEX_LOW_DOWN: + _simplex_low = max(_simplex_low - 1, 0); + window_invalidate(w); + break; + case WIDX_SIMPLEX_HIGH_UP: + _simplex_high = min(_simplex_high + 1, 36); + window_invalidate(w); + break; + case WIDX_SIMPLEX_HIGH_DOWN: + _simplex_high = max(_simplex_high - 1, 0); + window_invalidate(w); + break; + case WIDX_SIMPLEX_BASE_FREQ_UP: + _simplex_base_freq = min(_simplex_base_freq + 5, 1000); + window_invalidate(w); + break; + case WIDX_SIMPLEX_BASE_FREQ_DOWN: + _simplex_base_freq = max(_simplex_base_freq - 5, 0); + window_invalidate(w); + break; + case WIDX_SIMPLEX_OCTAVES_UP: + _simplex_octaves = min(_simplex_octaves + 1, 10); + window_invalidate(w); + break; + case WIDX_SIMPLEX_OCTAVES_DOWN: + _simplex_octaves = max(_simplex_octaves - 1, 1); + window_invalidate(w); + break; + case WIDX_SIMPLEX_MAP_SIZE_UP: + _mapSize = min(_mapSize + 1, 256); + window_invalidate(w); + break; + case WIDX_SIMPLEX_MAP_SIZE_DOWN: + _mapSize = max(_mapSize - 1, 16); + window_invalidate(w); + break; + case WIDX_SIMPLEX_WATER_LEVEL_UP: + _waterLevel = min(_waterLevel + 2, 54); + window_invalidate(w); + break; + case WIDX_SIMPLEX_WATER_LEVEL_DOWN: + _waterLevel = max(_waterLevel - 2, 0); + window_invalidate(w); + break; + case WIDX_SIMPLEX_FLOOR_TEXTURE: + for (i = 0; i < 14; i++) { + gDropdownItemsFormat[i] = -1; + gDropdownItemsArgs[i] = SPR_FLOOR_TEXTURE_GRASS + window_land_floor_texture_order[i]; + if (window_land_floor_texture_order[i] == _floorTexture) + RCT2_GLOBAL(0x009DEBA2, sint16) = i; + } + window_dropdown_show_image( + w->x + widget->left, w->y + widget->top, + widget->bottom - widget->top, + w->colours[2], + 0, + 14, + 47, 36, + gAppropriateImageDropdownItemsPerRow[14] + ); + break; + case WIDX_SIMPLEX_WALL_TEXTURE: + for (i = 0; i < 4; i++) { + gDropdownItemsFormat[i] = -1; + gDropdownItemsArgs[i] = SPR_WALL_TEXTURE_ROCK + window_land_wall_texture_order[i]; + if (window_land_wall_texture_order[i] == _wallTexture) + RCT2_GLOBAL(0x009DEBA2, sint16) = i; + } + window_dropdown_show_image( + w->x + widget->left, w->y + widget->top, + widget->bottom - widget->top, + w->colours[2], + 0, + 4, + 47, 36, + gAppropriateImageDropdownItemsPerRow[4] + ); + break; + } +} + +static void window_mapgen_simplex_dropdown() +{ + int type; + short dropdownIndex, widgetIndex; + rct_window *w; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + switch (widgetIndex) { + case WIDX_SIMPLEX_FLOOR_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + + type = (dropdownIndex == -1) ? + _floorTexture : + *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_FLOOR_TEXTURE_GRASS; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) == type) { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = 255; + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = type; + _floorTexture = type; + } + window_invalidate(w); + break; + case WIDX_SIMPLEX_WALL_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + + type = (dropdownIndex == -1) ? + _wallTexture : + *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_WALL_TEXTURE_ROCK; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) == type) { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = 255; + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = type; + _wallTexture = type; + } + window_invalidate(w); + break; + } +} + +static void window_mapgen_simplex_update(rct_window *w) +{ + // Tab animation + if (++w->frame_no >= window_mapgen_tab_animation_loops[w->page]) + w->frame_no = 0; + widget_invalidate(w, WIDX_TAB_3); +} + +static void window_mapgen_simplex_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); + + if (w->widgets != window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_SIMPLEX]) { + w->widgets = window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_SIMPLEX]; + window_init_scroll_widgets(w); + } + + w->widgets[WIDX_SIMPLEX_FLOOR_TEXTURE].image = SPR_FLOOR_TEXTURE_GRASS + _floorTexture; + w->widgets[WIDX_SIMPLEX_WALL_TEXTURE].image = SPR_WALL_TEXTURE_ROCK + _wallTexture; + + window_mapgen_set_pressed_tab(w); + window_mapgen_anchor_border_widgets(w); +} + +static void window_mapgen_simplex_paint() +{ + uint16 arg; + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_mapgen_draw_tab_images(dpi, w); + + gfx_draw_string_left(dpi, 2686, 0, 0, w->x + 5, w->y + w->widgets[WIDX_SIMPLEX_LOW].top + 1); + gfx_draw_string_left(dpi, 2687, 0, 0, w->x + 5, w->y + w->widgets[WIDX_SIMPLEX_HIGH].top + 1); + gfx_draw_string_left(dpi, 2688, 0, 0, w->x + 5, w->y + w->widgets[WIDX_SIMPLEX_BASE_FREQ].top + 1); + gfx_draw_string_left(dpi, 2689, 0, 0, w->x + 5, w->y + w->widgets[WIDX_SIMPLEX_OCTAVES].top + 1); + gfx_draw_string_left(dpi, STR_MAP_SIZE, 0, 0, w->x + 5, w->y + w->widgets[WIDX_SIMPLEX_MAP_SIZE].top + 1); + gfx_draw_string_left(dpi, 2692, 0, 0, w->x + 5, w->y + w->widgets[WIDX_SIMPLEX_WATER_LEVEL].top + 1); + + gfx_draw_string_left(dpi, 1737, &_simplex_low, w->colours[1], w->x + w->widgets[WIDX_SIMPLEX_LOW].left + 1, w->y + w->widgets[WIDX_SIMPLEX_LOW].top + 1); + gfx_draw_string_left(dpi, 1737, &_simplex_high, w->colours[1], w->x + w->widgets[WIDX_SIMPLEX_HIGH].left + 1, w->y + w->widgets[WIDX_SIMPLEX_HIGH].top + 1); + gfx_draw_string_left(dpi, 3311, &_simplex_base_freq, w->colours[1], w->x + w->widgets[WIDX_SIMPLEX_BASE_FREQ].left + 1, w->y + w->widgets[WIDX_SIMPLEX_BASE_FREQ].top + 1); + gfx_draw_string_left(dpi, 1737, &_simplex_octaves, w->colours[1], w->x + w->widgets[WIDX_SIMPLEX_OCTAVES].left + 1, w->y + w->widgets[WIDX_SIMPLEX_OCTAVES].top + 1); + + uint16 mapSizeArgs[2] = { _mapSize, _mapSize }; + gfx_draw_string_left(dpi, 839, mapSizeArgs, w->colours[1], w->x + w->widgets[WIDX_SIMPLEX_MAP_SIZE].left + 1, w->y + w->widgets[WIDX_SIMPLEX_MAP_SIZE].top + 1); + + arg = (_waterLevel - 12) / 2; + gfx_draw_string_left(dpi, 1737, &arg, w->colours[1], w->x + w->widgets[WIDX_SIMPLEX_WATER_LEVEL].left + 1, w->y + w->widgets[WIDX_SIMPLEX_WATER_LEVEL].top + 1); +} + +#pragma endregion + +#pragma region Common + +static void window_mapgen_set_page(rct_window *w, int page) +{ + w->page = page; + w->frame_no = 0; + if (w->viewport != NULL) { + w->viewport->width = 0; + w->viewport = NULL; + } + + w->enabled_widgets = window_mapgen_page_enabled_widgets[page]; + w->hold_down_widgets = window_mapgen_page_hold_down_widgets[page]; + w->event_handlers = window_mapgen_page_events[page]; + w->widgets = window_mapgen_page_widgets[page]; + w->disabled_widgets = 0; + w->pressed_widgets = 0; + + window_init_scroll_widgets(w); + window_invalidate(w); +} + +static void window_mapgen_set_pressed_tab(rct_window *w) +{ + int i; + for (i = 0; i < WINDOW_MAPGEN_PAGE_COUNT; i++) + w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); +} + +static void window_mapgen_anchor_border_widgets(rct_window *w) +{ + int width = w->widgets[WIDX_GENERATE].right - w->widgets[WIDX_GENERATE].left; + int height = w->widgets[WIDX_GENERATE].bottom - w->widgets[WIDX_GENERATE].top; + + w->widgets[WIDX_GENERATE].left = w->width - 3 - width; + w->widgets[WIDX_GENERATE].right = w->width - 3; + w->widgets[WIDX_GENERATE].bottom = w->height - 3; + w->widgets[WIDX_GENERATE].top = w->height - 3 - height; + + w->widgets[WIDX_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_TITLE].right = w->width - 2; + w->widgets[WIDX_CLOSE].left = w->width - 13; + w->widgets[WIDX_CLOSE].right = w->width - 3; +} + +static void window_mapgen_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int page, int spriteIndex) +{ + int widgetIndex = WIDX_TAB_1 + page; + + if (!(w->disabled_widgets & (1LL << widgetIndex))) { + if (w->page == page) { + int frame = w->frame_no / window_mapgen_tab_animation_divisor[w->page]; + spriteIndex += (frame % window_mapgen_tab_animation_frames[w->page]); + } + + gfx_draw_sprite(dpi, spriteIndex, w->x + w->widgets[widgetIndex].left, w->y + w->widgets[widgetIndex].top, 0); + } +} + +static void window_mapgen_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) +{ + window_mapgen_draw_tab_image(dpi, w, WINDOW_MAPGEN_PAGE_BASE, SPR_G2_TAB_LAND); + window_mapgen_draw_tab_image(dpi, w, WINDOW_MAPGEN_PAGE_RANDOM, SPR_G2_TAB_TREE); + window_mapgen_draw_tab_image(dpi, w, WINDOW_MAPGEN_PAGE_SIMPLEX, SPR_G2_TAB_PENCIL); +} + +#pragma endregion diff --git a/src/windows/music_credits.c b/src/windows/music_credits.c index 63158c5bbe..1c628bde81 100644 --- a/src/windows/music_credits.c +++ b/src/windows/music_credits.c @@ -88,15 +88,13 @@ void window_music_credits_open() if (window != NULL) return; - window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 255, - max(28, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 157), + window = window_create_centred( 510, 314, (uint32*)window_music_credits_events, WC_MUSIC_CREDITS, 0 - ); + ); window->widgets = window_music_credits_widgets; window->enabled_widgets = 1 << WIDX_CLOSE; @@ -132,13 +130,11 @@ static void window_music_credits_mouseup() */ static void window_music_credits_scrollgetsize() { - int y = 560; + int width, height; - #ifdef _MSC_VER - __asm mov edx, y - #else - __asm__("mov edx, %[y] " : [y] "+m" (y)); - #endif + width = 0; + height = 560; + window_scrollsize_set_registers(width, height); } /** diff --git a/src/windows/new_campaign.c b/src/windows/new_campaign.c index b21dc913e7..f64a894d51 100644 --- a/src/windows/new_campaign.c +++ b/src/windows/new_campaign.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../localisation/localisation.h" #include "../interface/widget.h" @@ -26,6 +27,7 @@ #include "../management/marketing.h" #include "../ride/ride.h" #include "dropdown.h" +#include "../interface/themes.h" #define SELECTED_RIDE_UNDEFINED ((uint16)0xFFFF) @@ -100,13 +102,13 @@ static void* window_new_campaign_events[] = { uint8 window_new_campaign_rides[MAX_RIDES]; uint8 window_new_campaign_shop_items[64]; -int ride_reliability_compare(const void *a, const void *b) +int ride_value_compare(const void *a, const void *b) { rct_ride *rideA, *rideB; rideA = GET_RIDE(*((uint8*)a)); rideB = GET_RIDE(*((uint8*)b)); - return rideB->reliability - rideA->reliability; + return rideB->value - rideA->value; } int ride_name_compare(const void *a, const void *b) @@ -129,8 +131,6 @@ int ride_name_compare(const void *a, const void *b) */ void window_new_campaign_open(sint16 campaignType) { - // RCT2_CALLPROC_X(0x0069E16F, campaignType, 0, 0, 0, 0, 0, 0); - rct_window *w; rct_ride *ride; int i, numApplicableRides; @@ -152,11 +152,10 @@ void window_new_campaign_open(sint16 campaignType) (1 << WIDX_WEEKS_INCREASE_BUTTON) | (1 << WIDX_WEEKS_DECREASE_BUTTON) | (1 << WIDX_START_BUTTON); - w->var_020 = 0x300; + w->hold_down_widgets = + (1 << WIDX_WEEKS_INCREASE_BUTTON) | + (1 << WIDX_WEEKS_DECREASE_BUTTON); window_init_scroll_widgets(w); - w->colours[0] = 19; - w->colours[1] = 19; - w->colours[2] = 19; window_new_campaign_widgets[WIDX_TITLE].image = STR_MARKETING_VOUCHERS_FOR_FREE_ENTRY_TO_THE_PARK + campaignType; @@ -173,19 +172,20 @@ void window_new_campaign_open(sint16 campaignType) numApplicableRides = 0; window_new_campaign_rides[0] = 255; FOR_ALL_RIDES(i, ride) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x03820000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP | RIDE_TYPE_FLAG_23 | RIDE_TYPE_FLAG_SELLS_DRINKS | RIDE_TYPE_FLAG_IS_BATHROOM)) window_new_campaign_rides[numApplicableRides++] = i; } - window_new_campaign_rides[numApplicableRides] = 255; // Take top 40 most reliable rides if (numApplicableRides > 40) { - qsort(window_new_campaign_rides, countof(window_new_campaign_rides), sizeof(uint8), ride_reliability_compare); + qsort(window_new_campaign_rides, countof(window_new_campaign_rides), sizeof(uint8), ride_value_compare); numApplicableRides = 40; } // Sort rides by name qsort(window_new_campaign_rides, numApplicableRides, sizeof(uint8), ride_name_compare); + + window_new_campaign_rides[numApplicableRides] = 255; } /** @@ -232,8 +232,7 @@ static void window_new_campaign_mouseup() window_close(w); break; case WIDX_START_BUTTON: - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_START_MARKETING_CAMPAIGN; - game_do_command(0, (w->campaign.no_weeks << 8) | 1, 0, (w->campaign.ride_id << 8) | w->campaign.campaign_type, GAME_COMMAND_START_MARKETING_CAMPAIGN, 0, 0); + marketing_start_campaign(w->campaign.campaign_type, w->campaign.ride_id, w->campaign.no_weeks); window_close(w); break; } @@ -273,34 +272,32 @@ static void window_new_campaign_mousedown(int widgetIndex, rct_window *w, rct_wi w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, numItems, dropdownWidget->right - dropdownWidget->left - 3 ); } } else { - if (window_new_campaign_rides[0] != 255) { - int numItems = 0; - for (int i = 0; i < 40; i++) { - if (window_new_campaign_rides[i] == 255) - break; + int numItems = 0; + for (int i = 0; i < 40; i++) { + if (window_new_campaign_rides[i] == 255) + break; - rct_ride *ride = GET_RIDE(window_new_campaign_rides[i]); - gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = (ride->name_arguments << 16) | ride->name; - numItems++; - } - - window_dropdown_show_text_custom_width( - w->x + dropdownWidget->left, - w->y + dropdownWidget->top, - dropdownWidget->bottom - dropdownWidget->top + 1, - w->colours[1], - 0x80, - numItems, - dropdownWidget->right - dropdownWidget->left - 3 - ); + rct_ride *ride = GET_RIDE(window_new_campaign_rides[i]); + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = ((uint64)ride->name_arguments << 16ULL) | ride->name; + numItems++; } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + numItems, + dropdownWidget->right - dropdownWidget->left - 3 + ); } break; case WIDX_WEEKS_INCREASE_BUTTON: @@ -349,6 +346,7 @@ static void window_new_campaign_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); window_new_campaign_widgets[WIDX_RIDE_LABEL].type = WWT_EMPTY; window_new_campaign_widgets[WIDX_RIDE_DROPDOWN].type = WWT_EMPTY; @@ -415,4 +413,4 @@ static void window_new_campaign_paint() // Total price money32 totalPrice = AdvertisingCampaignPricePerWeek[w->campaign.campaign_type] * w->campaign.no_weeks; gfx_draw_string_left(dpi, STR_MARKETING_TOTAL_COST, &totalPrice, 0, x, y); -} \ No newline at end of file +} diff --git a/src/windows/new_ride.c b/src/windows/new_ride.c index a05f4277e3..99518a8d95 100644 --- a/src/windows/new_ride.c +++ b/src/windows/new_ride.c @@ -19,15 +19,18 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../audio/audio.h" #include "../game.h" #include "../management/news_item.h" +#include "../management/research.h" #include "../ride/ride.h" #include "../localisation/localisation.h" #include "../world/scenery.h" #include "../ride/track.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../interface/themes.h" #define _window_new_ride_current_tab RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_SELECTED_TAB, uint8) @@ -43,7 +46,7 @@ const char RideTypeViewOrder[] = { RIDE_TYPE_MONORAIL, RIDE_TYPE_SUSPENDED_MONORAIL, RIDE_TYPE_CHAIRLIFT, - RIDE_TYPE_ELEVATOR, + RIDE_TYPE_LIFT, // Roller Coasters RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER, @@ -60,7 +63,7 @@ const char RideTypeViewOrder[] = { RIDE_TYPE_LOOPING_ROLLER_COASTER, RIDE_TYPE_STAND_UP_ROLLER_COASTER, RIDE_TYPE_CORKSCREW_ROLLER_COASTER, - RIDE_TYPE_90, + RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER, RIDE_TYPE_TWISTER_ROLLER_COASTER, RIDE_TYPE_GIGA_COASTER, RIDE_TYPE_SUSPENDED_SWINGING_COASTER, @@ -91,7 +94,7 @@ const char RideTypeViewOrder[] = { RIDE_TYPE_CAR_RIDE, RIDE_TYPE_MINI_HELICOPTERS, RIDE_TYPE_SPIRAL_SLIDE, - RIDE_TYPE_BUMPER_CARS, + RIDE_TYPE_DODGEMS, RIDE_TYPE_SPACE_RINGS, RIDE_TYPE_CIRCUS_SHOW, RIDE_TYPE_GHOST_TRAIN, @@ -116,7 +119,7 @@ const char RideTypeViewOrder[] = { RIDE_TYPE_RIVER_RAPIDS, RIDE_TYPE_SPLASH_BOATS, RIDE_TYPE_SUBMARINE_RIDE, - RIDE_TYPE_BUMPER_BOATS, + RIDE_TYPE_BOAT_RIDE, RIDE_TYPE_RIVER_RAFTS, RIDE_TYPE_WATER_COASTER, @@ -129,8 +132,8 @@ const char RideTypeViewOrder[] = { RIDE_TYPE_22, RIDE_TYPE_INFORMATION_KIOSK, RIDE_TYPE_FIRST_AID, - RIDE_TYPE_ATM, - RIDE_TYPE_BATHROOM + RIDE_TYPE_CASH_MACHINE, + RIDE_TYPE_TOILETS }; #pragma endregion @@ -314,7 +317,7 @@ static void window_new_ride_populate_list() if (currentCategory != rideEntry->category[0] && currentCategory != rideEntry->category[1]) continue; - if (rideEntry->var_008 & 0x2000) { + if (rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE) { dh &= ~4; nextListItem->type = rideType; nextListItem->entry_index = rideEntryIndex; @@ -325,7 +328,7 @@ static void window_new_ride_populate_list() nextListItem->entry_index = rideEntryIndex; nextListItem++; } else if (dh & 4) { - if (rideType == rideEntry->var_00C) { + if (rideType == rideEntry->ride_type[0]) { nextListItem--; nextListItem->type = rideType; nextListItem->entry_index = rideEntryIndex; @@ -346,14 +349,8 @@ static void window_new_ride_populate_list() */ static void window_new_ride_scroll_to_focused_ride(rct_window *w) { - int eax, ebx, ecx, edx, esi, edi, ebp; - - // Get the scroll height - eax = 0; - esi = (int)w; - RCT2_CALLFUNC_X(w->event_handlers[WE_SCROLL_GETSIZE], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - int scrollHeight = edx; - ebx = 0; + int scrollWidth, scrollHeight; + window_get_scroll_size(w, 0, &scrollWidth, &scrollHeight); // Find row index of the focused ride type rct_widget *listWidget = &window_new_ride_widgets[WIDX_RIDE_LIST]; @@ -381,19 +378,19 @@ static void window_new_ride_scroll_to_focused_ride(rct_window *w) * * rct2: 0x006B3CFF */ -void window_new_ride_open() +rct_window *window_new_ride_open() { rct_window *w; w = window_bring_to_front_by_class(WC_CONSTRUCT_RIDE); if (w != NULL) - return; + return w; // Not sure what these windows are window_close_by_class(WC_TRACK_DESIGN_LIST); window_close_by_class(WC_TRACK_DESIGN_PLACE); - w = window_create_auto_pos(601, 370, (uint32*)window_new_ride_events, WC_CONSTRUCT_RIDE, 0x400); + w = window_create_auto_pos(601, 370, (uint32*)window_new_ride_events, WC_CONSTRUCT_RIDE, WF_10); w->widgets = window_new_ride_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -409,9 +406,7 @@ void window_new_ride_open() window_init_scroll_widgets(w); w->frame_no = 0; - w->colours[0] = 24; - w->colours[1] = 26; - w->colours[2] = 26; + w->new_ride.selected_ride_id = -1; w->new_ride.highlighted_ride_id = -1; _lastTrackDesignCountRideType.type = 255; @@ -426,6 +421,17 @@ void window_new_ride_open() w->width = 1; window_new_ride_refresh_widget_sizing(w); window_new_ride_scroll_to_focused_ride(w); + + return w; +} + +rct_window *window_new_ride_open_research() +{ + rct_window *w; + + w = window_new_ride_open(); + window_new_ride_set_page(w, WINDOW_NEW_RIDE_PAGE_RESEARCH); + return w; } /** @@ -446,7 +452,7 @@ void window_new_ride_focus(ride_list_item rideItem) ride_list_item *listItem = (ride_list_item*)0x00F43523; while (listItem->type != RIDE_TYPE_NULL) { - if (listItem->type == rideItem.type && listItem->entry_index == rideItem.type) { + if (listItem->type == rideItem.type && listItem->entry_index == rideItem.entry_index) { RCT2_GLOBAL(0x00F43825, uint8) = rideItem.type; RCT2_GLOBAL(0x00F43826, uint8) = rideItem.entry_index; w->new_ride.highlighted_ride_id = (rideItem.entry_index << 8) | rideItem.type; @@ -541,7 +547,7 @@ static void window_new_ride_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w { int widgetIndex = WIDX_TAB_1 + page; - if (!(w->disabled_widgets & (1LL << widgetIndex))) { + if (w->widgets[widgetIndex].type != WWT_EMPTY && !(w->disabled_widgets & (1LL << widgetIndex))) { int frame = 0; if (_window_new_ride_current_tab == page) frame = w->frame_no / window_new_ride_tab_animation_divisor[page]; @@ -623,27 +629,17 @@ static void window_new_ride_update(rct_window *w) static void window_new_ride_scrollgetsize() { ride_list_item *listItem = (ride_list_item*)0x00F43523; - int scrollWidth, scrollHeight; + int width, height; int count = 0; while (listItem->type != 255 || listItem->entry_index != 255) { count++; listItem++; } - scrollWidth = 0; - scrollHeight = ((count + 4) / 5) * 116; + width = 0; + height = ((count + 4) / 5) * 116; - #ifdef _MSC_VER - __asm mov ecx, scrollWidth - #else - __asm__ ( "mov ecx, %[scrollWidth] " : [scrollWidth] "+m" (scrollWidth) ); - #endif - - #ifdef _MSC_VER - __asm mov edx, scrollHeight - #else - __asm__ ( "mov edx, %[scrollHeight] " : [scrollHeight] "+m" (scrollHeight) ); - #endif + window_scrollsize_set_registers(width, height); } /** @@ -652,14 +648,15 @@ static void window_new_ride_scrollgetsize() */ static void window_new_ride_scrollmousedown() { - short x, y; + short x, y, scrollIndex; rct_window *w; ride_list_item item; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); - if (RCT2_GLOBAL(0x009DEA6E, uint8) != 0) - return; + // Made it impossible to click a ride in pause mode. Since the UI now stays responsive in pause mode, always allow clicking a ride. + /*if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) + return;*/ item = window_new_ride_scroll_get_ride_list_item_at(w, x, y); if (item.type == 255 && item.entry_index == 255) @@ -679,11 +676,11 @@ static void window_new_ride_scrollmousedown() */ static void window_new_ride_scrollmouseover() { - short x, y; + short x, y, scrollIndex; rct_window *w; ride_list_item item; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); if (w->new_ride.selected_ride_id != -1) return; @@ -716,6 +713,7 @@ static void window_new_ride_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); window_new_ride_set_pressed_tab(w); @@ -759,43 +757,58 @@ static void window_new_ride_paint() int x = w->x + 10; int y = w->y + window_new_ride_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].top + 12; + rct_string_id stringId; - // Research type - rct_string_id stringId = STR_RESEARCH_UNKNOWN; - if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { - stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8); - if (RCT2_GLOBAL(0x01357CF3, uint8) != 1) { - uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint32); - if (typeId >= 0x10000) { - rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); - stringId = rideEntry->var_008 & 0x1000 ? - rideEntry->name : - (typeId & 0xFF00) + 2; - } else { - stringId = g_scenerySetEntries[typeId]->name; + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) == RESEARCH_STAGE_FINISHED_ALL){ + stringId = STR_RESEARCH_UNKNOWN; + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0); + y += 25; + // Progress + stringId = 2680; + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); + y += 15; + + RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; + gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); + } + else{ + // Research type + stringId = STR_RESEARCH_UNKNOWN; + if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { + stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8); + if (RCT2_GLOBAL(0x01357CF3, uint8) != 1) { + uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint32); + if (typeId >= 0x10000) { + rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); + stringId = rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME ? + rideEntry->name : + (typeId & 0xFF00) + 2; + } + else { + stringId = g_scenerySetEntries[typeId]->name; + } } } - } - gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0); - y += 25; + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0); + y += 25; - // Progress - stringId = 2285 + RCT2_GLOBAL(0x01357CF3, uint8); - gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); - y += 15; + // Progress + stringId = 2285 + RCT2_GLOBAL(0x01357CF3, uint8); + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); + y += 15; - // Expected - RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; - if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { - uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8); - if (expectedDay != 255) { - RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay; - RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_MONTH_MARCH + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8); - RCT2_GLOBAL(0x013CE952, uint16) = 2289; + // Expected + RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; + if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { + uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8); + if (expectedDay != 255) { + RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay; + RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_MONTH_MARCH + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8); + RCT2_GLOBAL(0x013CE952, uint16) = 2289; + } } + gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); } - gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); - // Last development x = w->x + 10; y = w->y + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_GROUP].top + 12; @@ -805,7 +818,7 @@ static void window_new_ride_paint() if (typeId != 0xFFFFFFFF) { if (typeId >= 0x10000) { rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); - stringId = rideEntry->var_008 & 0x1000 ? + stringId = rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME ? rideEntry->name : ((typeId >> 8) & 0xFF) + 2; @@ -849,13 +862,13 @@ static void window_new_ride_scrollpaint() // Draw ride image rideEntry = rideEntries[listItem->entry_index]; - int unk = rideEntry->var_004; - if (listItem->type != rideEntry->var_00C) { - unk++; - if (listItem->type != rideEntry->var_00D) - unk++; + int image_id = rideEntry->images_offset; + if (listItem->type != rideEntry->ride_type[0]) { + image_id++; + if (listItem->type != rideEntry->ride_type[1]) + image_id++; } - RCT2_CALLPROC_X(0x00681DE2, 0, 29013, x + 2, y + 2, 0xA0, (int)dpi, unk); + RCT2_CALLPROC_X(0x00681DE2, 0, 29013, x + 2, y + 2, 0xA0, (int)dpi, image_id); // Next position x += 116; @@ -924,7 +937,7 @@ static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixeli // Ride name and description rct_string_id rideName = rideEntry->name; rct_string_id rideDescription = rideEntry->description; - if (!(rideEntry->var_008 & 0x1000)) { + if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME)) { rideName = item.type + 2; rideDescription = item.type + 512; } @@ -934,8 +947,7 @@ static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixeli gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, width, 1690, 0); // Number of designs available - uint32 rideTypeFlags = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (item.type * 8), uint32); - if (rideTypeFlags & 0x10000000) { + if (ride_type_has_flag(item.type, RIDE_TYPE_FLAG_HAS_TRACK)) { if (item.type != _lastTrackDesignCountRideType.type || item.entry_index != _lastTrackDesignCountRideType.entry_index) { _lastTrackDesignCountRideType = item; _lastTrackDesignCount = get_num_track_designs(item); @@ -953,7 +965,7 @@ static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixeli stringId = 3340; break; } - gfx_draw_string_left(dpi, stringId, &_lastTrackDesignCount, 0, x, y + 40); + gfx_draw_string_left(dpi, stringId, &_lastTrackDesignCount, 0, x, y + 39); } // Price @@ -961,7 +973,7 @@ static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixeli // Get price of ride int unk2 = RCT2_GLOBAL(0x0097CC68 + (item.type * 2), uint8); money32 price = RCT2_GLOBAL(0x0097DD78 + (item.type * 4), uint16); - if (rideTypeFlags & 0x80000) { + if (ride_type_has_flag(item.type, RIDE_TYPE_FLAG_SELLS_FOOD)) { price *= RCT2_ADDRESS(0x0099DE34, uint32)[unk2]; } else { price *= RCT2_ADDRESS(0x0099DA34, uint32)[unk2]; @@ -970,10 +982,10 @@ static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixeli // rct_string_id stringId = 1691; - if (!(rideTypeFlags & 0x8000)) + if (!ride_type_has_flag(item.type, RIDE_TYPE_FLAG_15)) stringId++; - gfx_draw_string_right(dpi, stringId, &price, 0, x + width, y + 40); + gfx_draw_string_right(dpi, stringId, &price, 0, x + width, y + 39); } } @@ -989,8 +1001,7 @@ static void window_new_ride_select(rct_window *w) window_close(w); - uint32 rideTypeFlags = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (item.type * 8), uint32); - if (rideTypeFlags & 0x10000000) { + if (ride_type_has_flag(item.type, RIDE_TYPE_FLAG_HAS_TRACK)) { track_load_list(item); uint8 *trackDesignList = (uint8*)0x00F441EC; diff --git a/src/windows/news.c b/src/windows/news.c index 38948473e1..512bff4d0e 100644 --- a/src/windows/news.c +++ b/src/windows/news.c @@ -23,9 +23,11 @@ #include "../management/news_item.h" #include "../localisation/localisation.h" #include "../world/sprite.h" +#include "../peep/staff.h" #include "../sprites.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../interface/themes.h" enum WINDOW_NEWS_WIDGET_IDX { WIDX_BACKGROUND, @@ -48,6 +50,7 @@ static void window_news_update(rct_window *w); static void window_news_scrollgetsize(); static void window_news_scrollmousedown(); static void window_news_tooltip(); +static void window_news_invalidate(); static void window_news_paint(); static void window_news_scrollpaint(); @@ -77,7 +80,7 @@ static void* window_news_events[] = { window_news_tooltip, window_news_emptysub, window_news_emptysub, - window_news_emptysub, + window_news_invalidate, window_news_paint, window_news_scrollpaint }; @@ -103,9 +106,6 @@ void window_news_open() window->widgets = window_news_widgets; window->enabled_widgets = (1 << WIDX_CLOSE); window_init_scroll_widgets(window); - window->colours[0] = 1; - window->colours[1] = 1; - window->colours[2] = 0; window->news.var_480 = -1; } @@ -117,6 +117,7 @@ void window_news_open() widget = &window_news_widgets[WIDX_SCROLL]; window->scrolls[0].v_top = max(0, height - (widget->bottom - widget->top - 1)); widget_scroll_update_thumbs(window, WIDX_SCROLL); + } /** @@ -183,9 +184,10 @@ static void window_news_update(rct_window *w) */ static void window_news_scrollgetsize() { - int i, height; + int i, width, height; rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); + width = 0; height = 0; for (i = 11; i < 61; i++) { if (newsItems[i].type == NEWS_ITEM_NULL) @@ -194,12 +196,7 @@ static void window_news_scrollgetsize() height += 42; } - #ifdef _MSC_VER - __asm mov edx, height - #else - __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); - #endif - + window_scrollsize_set_registers(width, height); } /** @@ -209,11 +206,11 @@ static void window_news_scrollgetsize() static void window_news_scrollmousedown() { int i, buttonIndex; - short x, y; + short x, y, scrollIndex; rct_window *w; rct_news_item *newsItems; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); buttonIndex = 0; newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); @@ -281,6 +278,14 @@ static void window_news_paint() window_draw_widgets(w, dpi); } +static void window_news_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + /** * * rct2: 0x0066E4EE @@ -339,12 +344,34 @@ static void window_news_scrollpaint() case NEWS_ITEM_RIDE: gfx_draw_sprite(dpi, SPR_RIDE, x, yy, 0); break; - case NEWS_ITEM_PEEP_ON_RIDE: - // TODO - break; case NEWS_ITEM_PEEP: - // TODO - break; + case NEWS_ITEM_PEEP_ON_RIDE: + { + rct_drawpixelinfo* cliped_dpi = clip_drawpixelinfo(dpi, x + 1, 22, yy + 1, 22); + if (!cliped_dpi) break; + + rct_peep* peep = GET_PEEP(newsItem->assoc); + int clip_x = 10, clip_y = 19; + + // If normal peep set sprite to normal (no food) + // If staff set sprite to staff sprite + int sprite_type = 0; + if (peep->type == PEEP_TYPE_STAFF){ + sprite_type = peep->sprite_type; + if (peep->staff_type == STAFF_TYPE_ENTERTAINER){ + clip_y += 3; + } + } + + uint32 image_id = *RCT2_ADDRESS(0x00982708, uint32*)[sprite_type * 2]; + image_id += 0xA0000001; + image_id |= (peep->tshirt_colour << 19) | (peep->trousers_colour << 24); + + gfx_draw_sprite(cliped_dpi, image_id, clip_x, clip_y, 0); + + rct2_free(cliped_dpi); + break; + } case NEWS_ITEM_MONEY: gfx_draw_sprite(dpi, SPR_FINANCE, x, yy, 0); break; diff --git a/src/windows/options.c b/src/windows/options.c index b91ea8c68a..fb46b70615 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -26,6 +26,7 @@ * Padding between the widgets and the window needs reducing, an artifact from originally being inside group boxes. */ +#include #include "../addresses.h" #include "../audio/audio.h" #include "../audio/mixer.h" @@ -35,19 +36,24 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" +#include "../platform/platform.h" #include "../sprites.h" -#include "../platform/osinterface.h" #include "dropdown.h" +#include "error.h" +#include "../interface/themes.h" -enum { +enum WINDOW_OPTIONS_PAGE { WINDOW_OPTIONS_PAGE_DISPLAY, WINDOW_OPTIONS_PAGE_CULTURE, WINDOW_OPTIONS_PAGE_AUDIO, - WINDOW_OPTIONS_PAGE_INPUT, + WINDOW_OPTIONS_PAGE_CONTROLS, WINDOW_OPTIONS_PAGE_MISC, + WINDOW_OPTIONS_PAGE_TWITCH, WINDOW_OPTIONS_PAGE_COUNT }; +#pragma region Widgets + enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, @@ -58,17 +64,26 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_TAB_3, WIDX_TAB_4, WIDX_TAB_5, + WIDX_TAB_6, - WIDX_RESOLUTION, + WIDX_PAGE_START, + + // Display + WIDX_RESOLUTION = WIDX_PAGE_START, WIDX_RESOLUTION_DROPDOWN, WIDX_FULLSCREEN, WIDX_FULLSCREEN_DROPDOWN, WIDX_TILE_SMOOTHING_CHECKBOX, WIDX_GRIDLINES_CHECKBOX, + WIDX_HARDWARE_DISPLAY_CHECKBOX, WIDX_CONSTRUCTION_MARKER, WIDX_CONSTRUCTION_MARKER_DROPDOWN, + WIDX_THEMES, + WIDX_THEMES_DROPDOWN, + WIDX_THEMES_BUTTON, - WIDX_LANGUAGE, + // Culture / Units + WIDX_LANGUAGE = WIDX_PAGE_START, WIDX_LANGUAGE_DROPDOWN, WIDX_CURRENCY, WIDX_CURRENCY_DROPDOWN, @@ -78,96 +93,178 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_TEMPERATURE_DROPDOWN, WIDX_HEIGHT_LABELS, WIDX_HEIGHT_LABELS_DROPDOWN, + WIDX_DATE_FORMAT, + WIDX_DATE_FORMAT_DROPDOWN, - WIDX_SOUND, + // Audio + WIDX_SOUND = WIDX_PAGE_START, WIDX_SOUND_DROPDOWN, - WIDX_MUSIC, - WIDX_MUSIC_DROPDOWN, - WIDX_SOUND_QUALITY, - WIDX_SOUND_QUALITY_DROPDOWN, - WIDX_SOUND_SW_BUFFER_CHECKBOX, - WIDX_SOUND_PAUSED_CHECKBOX, + WIDX_SOUND_CHECKBOX, + WIDX_MUSIC_CHECKBOX, + WIDX_TITLE_MUSIC, + WIDX_TITLE_MUSIC_DROPDOWN, + WIDX_MASTER_VOLUME, + WIDX_MUSIC_VOLUME, - WIDX_SCREEN_EDGE_SCROLLING, + // Controls + WIDX_SCREEN_EDGE_SCROLLING = WIDX_PAGE_START, WIDX_HOTKEY_DROPDOWN, + WIDX_TOOLBAR_SHOW_FINANCES, + WIDX_TOOLBAR_SHOW_RESEARCH, + WIDX_TOOLBAR_SHOW_CHEATS, - WIDX_REAL_NAME_CHECKBOX, + // Misc + WIDX_REAL_NAME_CHECKBOX = WIDX_PAGE_START, WIDX_SAVE_PLUGIN_DATA_CHECKBOX, + WIDX_AUTOSAVE, + WIDX_AUTOSAVE_DROPDOWN, + WIDX_ALLOW_SUBTYPE_SWITCHING, + WIDX_TEST_UNFINISHED_TRACKS, + WIDX_AUTO_STAFF_PLACEMENT, + WIDX_DEBUGGING_TOOLS, + WIDX_TITLE_SEQUENCE, + WIDX_TITLE_SEQUENCE_DROPDOWN, + + // Twitch + WIDX_CHANNEL_BUTTON = WIDX_PAGE_START, + WIDX_FOLLOWER_PEEP_NAMES_CHECKBOX, + WIDX_FOLLOWER_PEEP_TRACKING_CHECKBOX, + WIDX_CHAT_PEEP_NAMES_CHECKBOX, + WIDX_CHAT_PEEP_TRACKING_CHECKBOX, + WIDX_NEWS_CHECKBOX }; #define WW 310 -#define WH 135 +#define WH 183 -static rct_widget window_options_widgets[] = { - { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, - { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_OPTIONS_TITLE, STR_WINDOW_TITLE_TIP }, - { WWT_CLOSEBOX, 0, WW-13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, - { WWT_RESIZE, 1, 0, WW - 1, 43, WH - 1, 0xFFFFFFFF, STR_NONE }, - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_NONE }, - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_NONE }, - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_NONE }, - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_NONE }, - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_NONE }, +#define MAIN_OPTIONS_WIDGETS \ + { WWT_FRAME, 0, 0, WW-1, 0, WH-1, STR_NONE, STR_NONE }, \ + { WWT_CAPTION, 0, 1, WW-2, 1, 14, STR_OPTIONS_TITLE, STR_WINDOW_TITLE_TIP }, \ + { WWT_CLOSEBOX, 0, WW-13, WW-3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, \ + { WWT_RESIZE, 1, 0, WW-1, 43, WH-1, 0xFFFFFFFF, STR_NONE }, \ + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 5266 }, \ + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 5267 }, \ + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 5268 }, \ + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 5269 }, \ + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 5270 }, \ + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 5271 } - // Display tab - { WWT_DROPDOWN, 0, 155, 299, 53, 64, 840, STR_NONE }, // resolution - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 54, 63, 876, STR_NONE }, - { WWT_DROPDOWN, 0, 155, 299, 68, 79, 871, STR_NONE }, // fullscreen - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 69, 78, 876, STR_NONE }, - { WWT_CHECKBOX, 0, 10, 299, 84, 95, STR_TILE_SMOOTHING, STR_TILE_SMOOTHING_TIP }, - { WWT_CHECKBOX, 0, 10, 299, 99, 110, STR_GRIDLINES, STR_GRIDLINES_TIP }, - { WWT_DROPDOWN, 0, 155, 299, 113, 124, STR_NONE, STR_NONE }, // construction marker - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 114, 123, 876, STR_NONE }, - - // Culture / units tab - { WWT_DROPDOWN, 0, 155, 299, 53, 64, STR_NONE, STR_NONE }, // language - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 54, 63, 876, STR_NONE }, - { WWT_DROPDOWN, 0, 155, 299, 68, 79, 871, STR_NONE }, // currency - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 69, 78, 876, STR_NONE }, // - { WWT_DROPDOWN, 0, 155, 299, 83, 94, 872, STR_NONE }, // distance - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 84, 93, 876, STR_NONE }, - { WWT_DROPDOWN, 0, 155, 299, 98, 110, 875, STR_NONE }, // temperature - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 99, 108, 876, STR_NONE }, //jjj - { WWT_DROPDOWN, 0, 155, 299, 113, 124, 868, STR_NONE }, // height labels - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 114, 123, 876, STR_NONE }, - - // Audio tab - { WWT_DROPDOWN, 0, 10, 299, 53, 64, 865, STR_NONE }, // sound - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 54, 63, 876, STR_NONE }, - { WWT_DROPDOWN, 0, 155, 299, 68, 79, 869, STR_NONE }, // music - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 69, 78, 876, STR_NONE }, - { WWT_DROPDOWN, 0, 155, 299, 83, 94, 870, STR_NONE }, // sound quality - { WWT_DROPDOWN_BUTTON, 0, 288, 298, 84, 93, 876, STR_NONE }, - { WWT_CHECKBOX, 0, 10, 299, 99, 110, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING_TIP }, - { WWT_CHECKBOX, 0, 10, 229, 114, 125, STR_SOUND, STR_NONE }, // enable/disable sound - - // Controls tab - { WWT_CHECKBOX, 2, 10, 299, 53, 64, STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP }, - { WWT_DROPDOWN_BUTTON, 0, 26, 185, 68, 78, STR_HOTKEY, STR_HOTKEY_TIP }, - - // Misc - { WWT_CHECKBOX, 2, 10, 299, 53, 64, STR_REAL_NAME, STR_REAL_NAME_TIP }, - { WWT_CHECKBOX, 2, 10, 299, 68, 79, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP }, +static rct_widget window_options_display_widgets[] = { + MAIN_OPTIONS_WIDGETS, + { WWT_DROPDOWN, 1, 155, 299, 53, 64, 840, STR_NONE }, // resolution + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 54, 63, 876, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 68, 79, 871, STR_NONE }, // fullscreen + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 69, 78, 876, STR_NONE }, + { WWT_CHECKBOX, 1, 10, 290, 84, 95, STR_TILE_SMOOTHING, STR_TILE_SMOOTHING_TIP }, // landscape smoothing + { WWT_CHECKBOX, 1, 10, 290, 99, 110, STR_GRIDLINES, STR_GRIDLINES_TIP }, // gridlines + { WWT_CHECKBOX, 1, 10, 290, 114, 125, 5154, STR_NONE }, // hardware display + { WWT_DROPDOWN, 1, 155, 299, 128, 139, STR_NONE, STR_NONE }, // construction marker + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 129, 138, 876, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 143, 154, STR_NONE, STR_NONE }, // colour schemes + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 144, 153, 876, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 26, 185, 159, 170, 5153, STR_NONE }, // colour schemes button { WIDGETS_END }, }; -const int window_options_tab_animation_divisor[] = { 4, 8, 2, 2, 2 }; -const int window_options_tab_animation_frames[] = { 16, 8, 16, 4, 16 }; +static rct_widget window_options_culture_widgets[] = { + MAIN_OPTIONS_WIDGETS, + { WWT_DROPDOWN, 1, 155, 299, 53, 64, STR_NONE, STR_NONE }, // language + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 54, 63, 876, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 68, 79, 871, STR_NONE }, // currency + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 69, 78, 876, STR_NONE }, // + { WWT_DROPDOWN, 1, 155, 299, 83, 94, 872, STR_NONE }, // distance + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 84, 93, 876, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 98, 110, 875, STR_NONE }, // temperature + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 99, 108, 876, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 113, 124, 868, STR_NONE }, // height labels + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 114, 123, 876, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 128, 139, STR_NONE, STR_NONE }, // date format + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 129, 138, 876, STR_NONE }, + { WIDGETS_END }, +}; + +static rct_widget window_options_audio_widgets[] = { + MAIN_OPTIONS_WIDGETS, + { WWT_DROPDOWN, 1, 10, 299, 53, 64, 865, STR_NONE }, // audio device + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 54, 63, 876, STR_NONE }, + { WWT_CHECKBOX, 1, 10, 229, 69, 80, STR_SOUND, STR_NONE }, // enable / disable sound + { WWT_CHECKBOX, 1, 10, 229, 84, 95, STR_MUSIC, STR_NONE }, // enable / disable music + { WWT_DROPDOWN, 1, 155, 299, 98, 109, STR_NONE, STR_NONE }, // title music + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 99, 108, 876, STR_NONE }, + { WWT_SCROLL, 1, 155, 299, 68, 80, 1, STR_NONE }, // master volume + { WWT_SCROLL, 1, 155, 299, 83, 95, 1, STR_NONE }, // music volume + { WIDGETS_END }, +}; + +static rct_widget window_options_controls_widgets[] = { + MAIN_OPTIONS_WIDGETS, + { WWT_CHECKBOX, 2, 10, 299, 54, 65, STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 26, 185, 69, 80, STR_HOTKEY, STR_HOTKEY_TIP }, + { WWT_CHECKBOX, 2, 10, 299, 84, 95, 5120, STR_NONE }, + { WWT_CHECKBOX, 2, 10, 299, 99, 110, 5121, STR_NONE }, + { WWT_CHECKBOX, 2, 10, 299, 114, 125, 5147, STR_NONE }, + { WIDGETS_END }, +}; + +static rct_widget window_options_misc_widgets[] = { + MAIN_OPTIONS_WIDGETS, + { WWT_CHECKBOX, 2, 10, 299, 54, 65, STR_REAL_NAME, STR_REAL_NAME_TIP }, + { WWT_CHECKBOX, 2, 10, 299, 69, 80, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP }, + { WWT_DROPDOWN, 1, 155, 299, 83, 94, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 84, 93, 876, STR_NONE }, + { WWT_CHECKBOX, 2, 10, 299, 99, 110, 5122, STR_NONE }, // allow subtype + { WWT_CHECKBOX, 2, 10, 299, 114, 125, 5155, 5156 }, // test unfinished tracks + { WWT_CHECKBOX, 2, 10, 299, 129, 140, 5343, STR_NONE }, // auto staff placement + { WWT_CHECKBOX, 2, 10, 299, 144, 155, 5150, STR_NONE }, // enabled debugging tools + { WWT_DROPDOWN, 1, 155, 299, 158, 169, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 159, 168, 876, STR_NONE }, + { WIDGETS_END }, +}; + +static rct_widget window_options_twitch_widgets[] = { + MAIN_OPTIONS_WIDGETS, + { WWT_DROPDOWN_BUTTON, 2, 10, 299, 54, 65, STR_TWITCH_NAME, STR_NONE }, // Twitch channel name + { WWT_CHECKBOX, 2, 10, 299, 69, 80, STR_TWITCH_PEEP_FOLLOWERS, STR_TWITCH_PEEP_FOLLOWERS_TIP }, // Twitch name peeps by follows + { WWT_CHECKBOX, 2, 10, 299, 84, 95, STR_TWITCH_FOLLOWERS_TRACK, STR_TWITCH_FOLLOWERS_TRACK_TIP }, // Twitch information on for follows + { WWT_CHECKBOX, 2, 10, 299, 99, 110, STR_TWITCH_PEEP_CHAT, STR_TWITCH_PEEP_CHAT_TIP }, // Twitch name peeps by chat + { WWT_CHECKBOX, 2, 10, 299, 114, 125, STR_TWITCH_CHAT_TRACK, STR_TWITCH_CHAT_TRACK_TIP }, // Twitch information on for chat + { WWT_CHECKBOX, 2, 10, 299, 129, 140, STR_TWITCH_CHAT_NEWS, STR_TWITCH_CHAT_NEWS_TIP }, // Twitch chat !news as notifications in game + { WIDGETS_END }, +}; + +rct_widget *window_options_page_widgets[] = { + window_options_display_widgets, + window_options_culture_widgets, + window_options_audio_widgets, + window_options_controls_widgets, + window_options_misc_widgets, + window_options_twitch_widgets +}; + +#pragma endregion + +const int window_options_tab_animation_divisor[] = { 4, 8, 2, 2, 2, 1 }; +const int window_options_tab_animation_frames[] = { 16, 8, 16, 4, 16, 1 }; static void window_options_set_page(rct_window *w, int page); static void window_options_set_pressed_tab(rct_window *w); static void window_options_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int page, int spriteIndex); static void window_options_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); +static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int num_items); +static void window_options_update_height_markers(); + +#pragma region Events static void window_options_emptysub() { } + static void window_options_mouseup(); static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); static void window_options_dropdown(); static void window_options_update(rct_window *w); static void window_options_invalidate(); static void window_options_paint(); -static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int num_items); -static void window_options_update_height_markers(); +static void window_options_scrollgetsize(); +static void window_options_text_input(); static void* window_options_events[] = { window_options_emptysub, @@ -185,11 +282,11 @@ static void* window_options_events[] = { window_options_emptysub, window_options_emptysub, window_options_emptysub, + window_options_scrollgetsize, window_options_emptysub, window_options_emptysub, window_options_emptysub, - window_options_emptysub, - window_options_emptysub, + window_options_text_input, window_options_emptysub, window_options_emptysub, window_options_emptysub, @@ -200,6 +297,86 @@ static void* window_options_events[] = { window_options_emptysub }; +#pragma endregion + +#pragma region Enabled Widgets + +#define MAIN_OPTIONS_ENABLED_WIDGETS \ + (1 << WIDX_CLOSE) | \ + (1 << WIDX_TAB_1) | \ + (1 << WIDX_TAB_2) | \ + (1 << WIDX_TAB_3) | \ + (1 << WIDX_TAB_4) | \ + (1 << WIDX_TAB_5) | \ + (1 << WIDX_TAB_6) + +static uint32 window_options_page_enabled_widgets[] = { + MAIN_OPTIONS_ENABLED_WIDGETS | + (1 << WIDX_RESOLUTION) | + (1 << WIDX_RESOLUTION_DROPDOWN) | + (1 << WIDX_FULLSCREEN) | + (1 << WIDX_FULLSCREEN_DROPDOWN) | + (1 << WIDX_TILE_SMOOTHING_CHECKBOX) | + (1 << WIDX_GRIDLINES_CHECKBOX) | + (1 << WIDX_HARDWARE_DISPLAY_CHECKBOX) | + (1 << WIDX_CONSTRUCTION_MARKER) | + (1 << WIDX_CONSTRUCTION_MARKER_DROPDOWN) | + (1 << WIDX_THEMES) | + (1 << WIDX_THEMES_DROPDOWN) | + (1 << WIDX_THEMES_BUTTON), + + MAIN_OPTIONS_ENABLED_WIDGETS | + (1 << WIDX_LANGUAGE) | + (1 << WIDX_LANGUAGE_DROPDOWN) | + (1 << WIDX_CURRENCY) | + (1 << WIDX_CURRENCY_DROPDOWN) | + (1 << WIDX_DISTANCE) | + (1 << WIDX_DISTANCE_DROPDOWN) | + (1 << WIDX_TEMPERATURE) | + (1 << WIDX_TEMPERATURE_DROPDOWN) | + (1 << WIDX_HEIGHT_LABELS) | + (1 << WIDX_HEIGHT_LABELS_DROPDOWN) | + (1 << WIDX_DATE_FORMAT) | + (1 << WIDX_DATE_FORMAT_DROPDOWN), + + MAIN_OPTIONS_ENABLED_WIDGETS | + (1 << WIDX_SOUND) | + (1 << WIDX_SOUND_DROPDOWN) | + (1 << WIDX_SOUND_CHECKBOX) | + (1 << WIDX_MUSIC_CHECKBOX) | + (1 << WIDX_TITLE_MUSIC) | + (1 << WIDX_TITLE_MUSIC_DROPDOWN), + + MAIN_OPTIONS_ENABLED_WIDGETS | + (1 << WIDX_SCREEN_EDGE_SCROLLING) | + (1 << WIDX_HOTKEY_DROPDOWN) | + (1 << WIDX_TOOLBAR_SHOW_FINANCES) | + (1 << WIDX_TOOLBAR_SHOW_RESEARCH) | + (1 << WIDX_TOOLBAR_SHOW_CHEATS), + + MAIN_OPTIONS_ENABLED_WIDGETS | + (1 << WIDX_REAL_NAME_CHECKBOX) | + (1 << WIDX_SAVE_PLUGIN_DATA_CHECKBOX) | + (1 << WIDX_AUTOSAVE) | + (1 << WIDX_AUTOSAVE_DROPDOWN) | + (1 << WIDX_ALLOW_SUBTYPE_SWITCHING) | + (1 << WIDX_TEST_UNFINISHED_TRACKS) | + (1 << WIDX_AUTO_STAFF_PLACEMENT) | + (1 << WIDX_DEBUGGING_TOOLS) | + (1 << WIDX_TITLE_SEQUENCE) | + (1 << WIDX_TITLE_SEQUENCE_DROPDOWN), + + MAIN_OPTIONS_ENABLED_WIDGETS | + (1 << WIDX_CHANNEL_BUTTON) | + (1 << WIDX_FOLLOWER_PEEP_NAMES_CHECKBOX) | + (1 << WIDX_FOLLOWER_PEEP_TRACKING_CHECKBOX) | + (1 << WIDX_CHAT_PEEP_NAMES_CHECKBOX) | + (1 << WIDX_CHAT_PEEP_TRACKING_CHECKBOX) | + (1 << WIDX_NEWS_CHECKBOX) +}; + +#pragma endregion + /** * * rct2: 0x006BAC5B @@ -213,53 +390,18 @@ void window_options_open() if (w != NULL) return; - w = window_create_auto_pos(WW, WH, (uint32*)window_options_events, WC_OPTIONS, 0); - w->widgets = window_options_widgets; - w->enabled_widgets = - (1ULL << WIDX_CLOSE) | - (1ULL << WIDX_TAB_1) | - (1ULL << WIDX_TAB_2) | - (1ULL << WIDX_TAB_3) | - (1ULL << WIDX_TAB_4) | - (1ULL << WIDX_TAB_5) | - (1ULL << WIDX_SOUND) | - (1ULL << WIDX_SOUND_DROPDOWN) | - (1ULL << WIDX_MUSIC) | - (1ULL << WIDX_MUSIC_DROPDOWN) | - (1ULL << WIDX_SOUND_QUALITY) | - (1ULL << WIDX_SOUND_QUALITY_DROPDOWN) | - (1ULL << WIDX_LANGUAGE) | - (1ULL << WIDX_LANGUAGE_DROPDOWN) | - (1ULL << WIDX_CURRENCY) | - (1ULL << WIDX_CURRENCY_DROPDOWN) | - (1ULL << WIDX_DISTANCE) | - (1ULL << WIDX_DISTANCE_DROPDOWN) | - (1ULL << WIDX_RESOLUTION) | - (1ULL << WIDX_RESOLUTION_DROPDOWN) | - (1ULL << WIDX_FULLSCREEN) | - (1ULL << WIDX_FULLSCREEN_DROPDOWN) | - (1ULL << WIDX_TEMPERATURE) | - (1ULL << WIDX_TEMPERATURE_DROPDOWN) | - (1ULL << WIDX_HOTKEY_DROPDOWN) | - (1ULL << WIDX_SCREEN_EDGE_SCROLLING) | - (1ULL << WIDX_REAL_NAME_CHECKBOX) | - (1ULL << WIDX_CONSTRUCTION_MARKER) | - (1ULL << WIDX_CONSTRUCTION_MARKER_DROPDOWN) | - (1ULL << WIDX_HEIGHT_LABELS) | - (1ULL << WIDX_HEIGHT_LABELS_DROPDOWN) | - (1ULL << WIDX_TILE_SMOOTHING_CHECKBOX) | - (1ULL << WIDX_GRIDLINES_CHECKBOX) | - (1ULL << WIDX_SOUND_SW_BUFFER_CHECKBOX) | - (1ULL << WIDX_SOUND_PAUSED_CHECKBOX) | - (1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX); // doesn't seem to work? - + w = window_create_centred(WW, WH, (uint32*)window_options_events, WC_OPTIONS, WF_RESIZABLE); + w->widgets = window_options_display_widgets; + w->enabled_widgets = window_options_page_enabled_widgets[WINDOW_OPTIONS_PAGE_DISPLAY]; w->page = WINDOW_OPTIONS_PAGE_DISPLAY; + w->frame_no = 0; window_init_scroll_widgets(w); - w->colours[0] = 7; - w->colours[1] = 7; - w->colours[2] = 7; + //window_invalidate(w); + + colour_scheme_update(w); } + /** * * rct2: 0x006BAFCA @@ -280,54 +422,163 @@ static void window_options_mouseup() case WIDX_TAB_3: case WIDX_TAB_4: case WIDX_TAB_5: + case WIDX_TAB_6: window_options_set_page(w, widgetIndex - WIDX_TAB_1); break; - case WIDX_HOTKEY_DROPDOWN: - window_shortcut_keys_open(); - break; - case WIDX_SCREEN_EDGE_SCROLLING: - gGeneral_config.edge_scrolling ^= 1; - config_save(); - window_invalidate(w); - break; - case WIDX_REAL_NAME_CHECKBOX: - RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; - RCT2_CALLPROC_X(0x0069C52F, RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES ? 0 : 1, 0, 0, 0, 0, 0, 0); - break; - case WIDX_TILE_SMOOTHING_CHECKBOX: - gGeneral_config.landscape_smoothing ^= 1; - config_save(); - gfx_invalidate_screen(); - break; - case WIDX_GRIDLINES_CHECKBOX: - gGeneral_config.always_show_gridlines ^= 1; - config_save(); - gfx_invalidate_screen(); - if ((w = window_get_main()) != NULL) { - if (gGeneral_config.always_show_gridlines) - w->viewport->flags |= VIEWPORT_FLAG_GRIDLINES; - else - w->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; + } + + switch (w->page) { + case WINDOW_OPTIONS_PAGE_DISPLAY: + switch (widgetIndex) { + case WIDX_TILE_SMOOTHING_CHECKBOX: + gConfigGeneral.landscape_smoothing ^= 1; + config_save_default(); + gfx_invalidate_screen(); + break; + case WIDX_GRIDLINES_CHECKBOX: + gConfigGeneral.always_show_gridlines ^= 1; + config_save_default(); + gfx_invalidate_screen(); + if ((w = window_get_main()) != NULL) { + if (gConfigGeneral.always_show_gridlines) + w->viewport->flags |= VIEWPORT_FLAG_GRIDLINES; + else + w->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; + } + break; + case WIDX_HARDWARE_DISPLAY_CHECKBOX: + gConfigGeneral.hardware_display ^= 1; + platform_refresh_video(); + config_save_default(); + window_invalidate(w); + break; + case WIDX_THEMES_BUTTON: + window_themes_open(); + window_invalidate(w); + break; } break; - case WIDX_SAVE_PLUGIN_DATA_CHECKBOX: - gGeneral_config.save_plugin_data ^= 1; - config_save(); - window_invalidate(w); + + case WINDOW_OPTIONS_PAGE_CULTURE: break; - case WIDX_SOUND_SW_BUFFER_CHECKBOX: - pause_sounds(); - gSound_config.forced_software_buffering ^= 1; - config_save(); - unpause_sounds(); - window_invalidate(w); + + case WINDOW_OPTIONS_PAGE_AUDIO: + switch (widgetIndex) { + case WIDX_SOUND_CHECKBOX: + toggle_all_sounds(); + config_save_default(); + window_invalidate(w); + break; + case WIDX_MUSIC_CHECKBOX: + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) ^= 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) == 0) + stop_ride_music(); + + gConfigSound.ride_music ^= 1; + config_save_default(); + window_invalidate(w); + break; + } break; - case WIDX_SOUND_PAUSED_CHECKBOX: - if (g_sounds_disabled) - unpause_sounds(); - else - pause_sounds(); - window_invalidate(w); + + case WINDOW_OPTIONS_PAGE_CONTROLS: + switch (widgetIndex) { + case WIDX_HOTKEY_DROPDOWN: + window_shortcut_keys_open(); + break; + case WIDX_SCREEN_EDGE_SCROLLING: + gConfigGeneral.edge_scrolling ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_TOOLBAR_SHOW_FINANCES: + gConfigInterface.toolbar_show_finances ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_RESEARCH: + gConfigInterface.toolbar_show_research ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TOOLBAR_SHOW_CHEATS: + gConfigInterface.toolbar_show_cheats ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + } + break; + + case WINDOW_OPTIONS_PAGE_MISC: + switch (widgetIndex) { + case WIDX_ALLOW_SUBTYPE_SWITCHING: + gConfigInterface.allow_subtype_switching ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_RIDE); + break; + case WIDX_DEBUGGING_TOOLS: + gConfigGeneral.debugging_tools ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_TEST_UNFINISHED_TRACKS: + gConfigGeneral.test_unfinished_tracks ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_REAL_NAME_CHECKBOX: + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; + RCT2_CALLPROC_X(0x0069C52F, RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES ? 0 : 1, 0, 0, 0, 0, 0, 0); + break; + case WIDX_SAVE_PLUGIN_DATA_CHECKBOX: + gConfigGeneral.save_plugin_data ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_AUTO_STAFF_PLACEMENT: + gConfigGeneral.auto_staff_placement ^= 1; + config_save_default(); + window_invalidate(w); + break; + } + break; + + case WINDOW_OPTIONS_PAGE_TWITCH: + switch (widgetIndex) { + case WIDX_CHANNEL_BUTTON: + window_text_input_raw_open(w, widgetIndex, STR_TWITCH_NAME, STR_TWITCH_NAME_DESC, gConfigTwitch.channel, 32); + break; + case WIDX_FOLLOWER_PEEP_NAMES_CHECKBOX: + gConfigTwitch.enable_follower_peep_names ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_FOLLOWER_PEEP_TRACKING_CHECKBOX: + gConfigTwitch.enable_follower_peep_tracking ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_CHAT_PEEP_NAMES_CHECKBOX: + gConfigTwitch.enable_chat_peep_names ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_CHAT_PEEP_TRACKING_CHECKBOX: + gConfigTwitch.enable_chat_peep_tracking ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_NEWS_CHECKBOX: + gConfigTwitch.enable_news ^= 1; + config_save_default(); + window_invalidate(w); + break; + } break; } } @@ -342,114 +593,212 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* widget = &w->widgets[widgetIndex - 1]; - switch (widgetIndex) { - case WIDX_SOUND_DROPDOWN: - // populate the list with the sound devices - for (i = 0; i < gAudioDeviceCount; i++) { - gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = 1170 | ((uint64)(intptr_t)gAudioDevices[i].name << 16); + switch (w->page) { + case WINDOW_OPTIONS_PAGE_DISPLAY: + switch (widgetIndex) { + case WIDX_RESOLUTION_DROPDOWN: + { + platform_update_fullscreen_resolutions(); + + int selectedResolution = -1; + for (i = 0; i < gNumResolutions; i++) { + resolution *resolution = &gResolutions[i]; + + gDropdownItemsFormat[i] = 1142; + + uint16 *args = (uint16*)&gDropdownItemsArgs[i]; + args[0] = 839; + args[1] = resolution->width; + args[2] = resolution->height; + + if (resolution->width == gConfigGeneral.fullscreen_width && resolution->height == gConfigGeneral.fullscreen_height) + selectedResolution = i; + } + + window_options_show_dropdown(w, widget, gNumResolutions); + + if (selectedResolution != -1 && selectedResolution < 32) + gDropdownItemsChecked = 1 << selectedResolution; } - window_options_show_dropdown(w, widget, gAudioDeviceCount); - - gDropdownItemsChecked |= (1 << RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32)); break; - case WIDX_HEIGHT_LABELS_DROPDOWN: - gDropdownItemsFormat[0] = 1142; - gDropdownItemsFormat[1] = 1142; - gDropdownItemsArgs[0] = STR_UNITS; - gDropdownItemsArgs[1] = STR_REAL_VALUES; + case WIDX_FULLSCREEN_DROPDOWN: + gDropdownItemsFormat[0] = 1142; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsFormat[2] = 1142; + gDropdownItemsArgs[0] = 2773; + gDropdownItemsArgs[1] = 2774; + gDropdownItemsArgs[2] = 2775; - window_options_show_dropdown(w, widget, 2); + window_options_show_dropdown(w, widget, 3); - gDropdownItemsChecked = gGeneral_config.show_height_as_units ? 1 : 2; - break; - case WIDX_MUSIC_DROPDOWN: - gDropdownItemsFormat[0] = 1142; - gDropdownItemsFormat[1] = 1142; - gDropdownItemsArgs[0] = STR_OFF; - gDropdownItemsArgs[1] = STR_ON; + gDropdownItemsChecked = 1 << gConfigGeneral.fullscreen_mode; + break; + case WIDX_CONSTRUCTION_MARKER_DROPDOWN: + gDropdownItemsFormat[0] = 1142; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsArgs[0] = STR_WHITE; + gDropdownItemsArgs[1] = STR_TRANSLUCENT; - window_options_show_dropdown(w, widget, 2); + window_options_show_dropdown(w, widget, 2); - gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8); - break; - case WIDX_SOUND_QUALITY_DROPDOWN: - num_items = 3; + gDropdownItemsChecked = 1 << gConfigGeneral.construction_marker_colour; + break; + case WIDX_THEMES_DROPDOWN: + num_items = gConfigThemes.num_presets; - for (i = 0; i < num_items; i++) { - gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = STR_SOUND_LOW + i; // low, medium, high + gDropdownItemsFormat[0] = 2777; + gDropdownItemsArgs[0] = (uint64)&gConfigThemes.presets[1].name; + gDropdownItemsFormat[1] = 2777; + gDropdownItemsArgs[1] = (uint64)&gConfigThemes.presets[0].name; + + for (i = 2; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint64)&gConfigThemes.presets[i].name; + } + + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + num_items, + widget->right - widget->left - 3 + ); + + if (gCurrentTheme == 0 || gCurrentTheme == 1) + gDropdownItemsChecked = 1 << (gCurrentTheme ^ 1); + else + gDropdownItemsChecked = 1 << (gCurrentTheme); + break; } - - window_options_show_dropdown(w, widget, num_items); - - gDropdownItemsChecked = 1 << gSound_config.sound_quality; break; - case WIDX_CURRENCY_DROPDOWN: - num_items = 10; - for (i = 0; i < num_items; i++) { - gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = STR_POUNDS + i; + case WINDOW_OPTIONS_PAGE_CULTURE: + switch (widgetIndex) { + case WIDX_HEIGHT_LABELS_DROPDOWN: + gDropdownItemsFormat[0] = 1142; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsArgs[0] = STR_UNITS; + gDropdownItemsArgs[1] = STR_REAL_VALUES; + + window_options_show_dropdown(w, widget, 2); + + gDropdownItemsChecked = gConfigGeneral.show_height_as_units ? 1 : 2; + break; + case WIDX_CURRENCY_DROPDOWN: + num_items = 10; + + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_POUNDS + i; + } + + window_options_show_dropdown(w, widget, num_items); + + gDropdownItemsChecked = 1 << gConfigGeneral.currency_format; + break; + case WIDX_DISTANCE_DROPDOWN: + gDropdownItemsFormat[0] = 1142; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsArgs[0] = STR_IMPERIAL; + gDropdownItemsArgs[1] = STR_METRIC; + + window_options_show_dropdown(w, widget, 2); + + gDropdownItemsChecked = 1 << gConfigGeneral.measurement_format; + break; + case WIDX_TEMPERATURE_DROPDOWN: + gDropdownItemsFormat[0] = 1142; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsArgs[0] = STR_CELSIUS; + gDropdownItemsArgs[1] = STR_FAHRENHEIT; + + window_options_show_dropdown(w, widget, 2); + + gDropdownItemsChecked = 1 << gConfigGeneral.temperature_format; + break; + case WIDX_LANGUAGE_DROPDOWN: + for (i = 1; i < LANGUAGE_COUNT; i++) { + gDropdownItemsFormat[i - 1] = 2777; + gDropdownItemsArgs[i - 1] = (sint64)language_names[i]; + } + window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1); + gDropdownItemsChecked = 1 << (gCurrentLanguage - 1); + break; + case WIDX_DATE_FORMAT_DROPDOWN: + for (i = 0; i < 2; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = 5162 + i; + } + window_options_show_dropdown(w, widget, 2); + gDropdownItemsChecked = 1 << (gConfigGeneral.date_format); + break; } - - window_options_show_dropdown(w, widget, num_items); - - gDropdownItemsChecked = 1 << gGeneral_config.currency_format; break; - case WIDX_DISTANCE_DROPDOWN: - gDropdownItemsFormat[0] = 1142; - gDropdownItemsFormat[1] = 1142; - gDropdownItemsArgs[0] = STR_IMPERIAL; - gDropdownItemsArgs[1] = STR_METRIC; - window_options_show_dropdown(w, widget, 2); + case WINDOW_OPTIONS_PAGE_AUDIO: + switch (widgetIndex) { + case WIDX_SOUND_DROPDOWN: + audio_get_devices(); - gDropdownItemsChecked = 1 << gGeneral_config.measurement_format; - break; - case WIDX_RESOLUTION_DROPDOWN: - // RCT2_CALLPROC_EBPSAFE(0x006BB2AF); - break; - case WIDX_FULLSCREEN_DROPDOWN: - gDropdownItemsFormat[0] = 1142; - gDropdownItemsFormat[1] = 1142; - gDropdownItemsFormat[2] = 1142; - gDropdownItemsArgs[0] = 2773; - gDropdownItemsArgs[1] = 2774; - gDropdownItemsArgs[2] = 2775; + // populate the list with the sound devices + for (i = 0; i < gAudioDeviceCount; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = 1170 | ((uint64)(intptr_t)gAudioDevices[i].name << 16); + } - window_options_show_dropdown(w, widget, 3); + window_options_show_dropdown(w, widget, gAudioDeviceCount); - gDropdownItemsChecked = 1 << gGeneral_config.fullscreen_mode; - break; - case WIDX_TEMPERATURE_DROPDOWN: - gDropdownItemsFormat[0] = 1142; - gDropdownItemsFormat[1] = 1142; - gDropdownItemsArgs[0] = STR_CELSIUS; - gDropdownItemsArgs[1] = STR_FAHRENHEIT; + gDropdownItemsChecked |= (1 << RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32)); + break; + case WIDX_TITLE_MUSIC_DROPDOWN: + num_items = 4; - window_options_show_dropdown(w, widget, 2); + for (i = 0; i < num_items - 1; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = 2739 + i; + } + // Random title music + gDropdownItemsFormat[3] = 1142; + gDropdownItemsArgs[3] = 5126; - gDropdownItemsChecked = 1 << gGeneral_config.temperature_format; - break; - case WIDX_CONSTRUCTION_MARKER_DROPDOWN: - gDropdownItemsFormat[0] = 1142; - gDropdownItemsFormat[1] = 1142; - gDropdownItemsArgs[0] = STR_WHITE; - gDropdownItemsArgs[1] = STR_TRANSLUCENT; + window_options_show_dropdown(w, widget, num_items); - window_options_show_dropdown(w, widget, 2); - - gDropdownItemsChecked = 1 << gGeneral_config.construction_marker_colour; - break; - case WIDX_LANGUAGE_DROPDOWN: - for (i = 1; i < LANGUAGE_COUNT; i++) { - gDropdownItemsFormat[i - 1] = 2777; - gDropdownItemsArgs[i - 1] = (sint64)language_names[i]; + gDropdownItemsChecked = 1 << gConfigSound.title_music; + break; } - window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1); - gDropdownItemsChecked = 1 << (gCurrentLanguage - 1); + break; + + case WINDOW_OPTIONS_PAGE_CONTROLS: + break; + + case WINDOW_OPTIONS_PAGE_MISC: + switch (widgetIndex) { + case WIDX_AUTOSAVE_DROPDOWN: + for (i = AUTOSAVE_EVERY_WEEK; i <= AUTOSAVE_NEVER; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = 2701 + i; + } + window_options_show_dropdown(w, widget, AUTOSAVE_NEVER + 1); + gDropdownItemsChecked = 1 << gConfigGeneral.autosave_frequency; + break; + case WIDX_TITLE_SEQUENCE_DROPDOWN: + gDropdownItemsFormat[0] = 1142; + gDropdownItemsArgs[0] = STR_TITLE_SEQUENCE_RCT2; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsArgs[1] = STR_TITLE_SEQUENCE_OPENRCT2; + window_options_show_dropdown(w, widget, 2); + if (gConfigGeneral.title_sequence == TITLE_SEQUENCE_RCT2) + gDropdownItemsChecked = 1 << 0; + else if (gConfigGeneral.title_sequence == TITLE_SEQUENCE_OPENRCT2) + gDropdownItemsChecked = 1 << 1; + break; + } + break; + + case WINDOW_OPTIONS_PAGE_TWITCH: break; } } @@ -469,189 +818,261 @@ static void window_options_dropdown() if (dropdownIndex == -1) return; - switch (widgetIndex) { - case WIDX_SOUND_DROPDOWN: - audio_init2(dropdownIndex); - if (dropdownIndex < gAudioDeviceCount) { -#ifdef USE_MIXER + switch (w->page) { + case WINDOW_OPTIONS_PAGE_DISPLAY: + switch (widgetIndex) { + case WIDX_RESOLUTION_DROPDOWN: + { + resolution *resolution = &gResolutions[dropdownIndex]; + if (resolution->width != gConfigGeneral.fullscreen_width || resolution->height != gConfigGeneral.fullscreen_height) { + gConfigGeneral.fullscreen_width = resolution->width; + gConfigGeneral.fullscreen_height = resolution->height; + + if (gConfigGeneral.fullscreen_mode == SDL_WINDOW_FULLSCREEN) + platform_set_fullscreen_mode(SDL_WINDOW_FULLSCREEN); + + config_save_default(); + gfx_invalidate_screen(); + } + } + break; + case WIDX_FULLSCREEN_DROPDOWN: + if (dropdownIndex != gConfigGeneral.fullscreen_mode){ + platform_set_fullscreen_mode(dropdownIndex); + + gConfigGeneral.fullscreen_mode = (uint8)dropdownIndex; + config_save_default(); + gfx_invalidate_screen(); + } + break; + case WIDX_CONSTRUCTION_MARKER_DROPDOWN: + if (dropdownIndex != gConfigGeneral.construction_marker_colour) { + gConfigGeneral.construction_marker_colour = (uint8)dropdownIndex; + config_save_default(); + gfx_invalidate_screen(); + } + break; + case WIDX_THEMES_DROPDOWN: + if (dropdownIndex != -1) { + if (dropdownIndex == 0 || dropdownIndex == 1) + dropdownIndex ^= 1; + theme_change_preset(dropdownIndex); + } + config_save_default(); + break; + } + break; + + case WINDOW_OPTIONS_PAGE_CULTURE: + switch (widgetIndex) { + case WIDX_HEIGHT_LABELS_DROPDOWN: + // reset flag and set it to 1 if height as units is selected + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= ~CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; + gConfigGeneral.show_height_as_units = 0; + if (dropdownIndex == 0) { - Mixer_Init(NULL); - } else { - Mixer_Init(gAudioDevices[dropdownIndex].name); + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; + gConfigGeneral.show_height_as_units = 1; } + + window_options_update_height_markers(); + break; + case WIDX_CURRENCY_DROPDOWN: + gConfigGeneral.currency_format = (sint8)dropdownIndex; + config_save_default(); + gfx_invalidate_screen(); + break; + case WIDX_DISTANCE_DROPDOWN: + gConfigGeneral.measurement_format = (sint8)dropdownIndex; + config_save_default(); + window_options_update_height_markers(); + break; + case WIDX_TEMPERATURE_DROPDOWN: + if (dropdownIndex != gConfigGeneral.temperature_format) { + gConfigGeneral.temperature_format = (sint8)dropdownIndex; + config_save_default(); + gfx_invalidate_screen(); + } + break; + case WIDX_LANGUAGE_DROPDOWN: + if (dropdownIndex != gCurrentLanguage - 1) { + language_open(dropdownIndex + 1); + gConfigGeneral.language = dropdownIndex + 1; + config_save_default(); + gfx_invalidate_screen(); + } + break; + case WIDX_DATE_FORMAT_DROPDOWN: + if (dropdownIndex != gConfigGeneral.date_format) { + gConfigGeneral.date_format = (uint8)dropdownIndex; + config_save_default(); + gfx_invalidate_screen(); + } + break; + } + break; + + case WINDOW_OPTIONS_PAGE_AUDIO: + switch (widgetIndex) { + case WIDX_SOUND_DROPDOWN: + audio_init2(dropdownIndex); + if (dropdownIndex < gAudioDeviceCount) { +#ifdef USE_MIXER + if (dropdownIndex == 0) { + Mixer_Init(NULL); + } + else { + Mixer_Init(gAudioDevices[dropdownIndex].name); + } #endif - } - /*#ifdef _MSC_VER - __asm movzx ax, dropdownIndex - #else - __asm__ ( "movzx ax, %[dropdownIndex] " : : [dropdownIndex] "g" ((char)dropdownIndex) ); - #endif - // the switch replaces ax value - RCT2_CALLPROC_EBPSAFE(0x006BA9B5); // part of init audio*/ - - window_invalidate(w); - break; - case WIDX_HEIGHT_LABELS_DROPDOWN: - // reset flag and set it to 1 if height as units is selected - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &= ~CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; - gGeneral_config.show_height_as_units = 0; - - if (dropdownIndex == 0) { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS; - gGeneral_config.show_height_as_units = 1; - } - - window_options_update_height_markers(); - break; - case WIDX_MUSIC_DROPDOWN: - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) = (uint8)dropdownIndex; - config_save(); - stop_ride_music();//RCT2_CALLPROC_EBPSAFE(0x006BCA9F); - window_invalidate(w); - break; - case WIDX_SOUND_QUALITY_DROPDOWN: - // TODO: no clue what this does (and if it's correct) - RCT2_GLOBAL(0x009AAC75, uint8) = RCT2_GLOBAL(0x009AF601 + dropdownIndex, uint8); - RCT2_GLOBAL(0x009AAC76, uint8) = RCT2_GLOBAL(0x009AF604 + dropdownIndex, uint8); - gSound_config.sound_quality = (sint8)dropdownIndex; - config_save(); - window_invalidate(w); - break; - case WIDX_CURRENCY_DROPDOWN: - gGeneral_config.currency_format = (sint8)dropdownIndex; - config_save(); - gfx_invalidate_screen(); - break; - case WIDX_DISTANCE_DROPDOWN: - gGeneral_config.measurement_format = (sint8)dropdownIndex; - config_save(); - window_options_update_height_markers(); - break; - case WIDX_RESOLUTION_DROPDOWN: - #ifdef _MSC_VER - __asm movzx ax, dropdownIndex - #else - __asm__ ( "movzx ax, %[dropdownIndex] " : : [dropdownIndex] "g" ((char)dropdownIndex) ); - #endif - // the switch replaces ax value - RCT2_CALLPROC_EBPSAFE(0x006BB37D); - break; - case WIDX_FULLSCREEN_DROPDOWN: - if (dropdownIndex != gGeneral_config.fullscreen_mode){ - if (dropdownIndex == 2){ - w->disabled_widgets |= (1 << WIDX_RESOLUTION_DROPDOWN); - w->disabled_widgets |= (1 << WIDX_RESOLUTION); - } else { - w->disabled_widgets &= ~(1 << WIDX_RESOLUTION_DROPDOWN); - w->disabled_widgets &= ~(1 << WIDX_RESOLUTION); } - osinterface_set_fullscreen_mode(dropdownIndex); + /*#ifdef _MSC_VER + __asm movzx ax, dropdownIndex + #else + __asm__ ( "movzx ax, %[dropdownIndex] " : : [dropdownIndex] "g" ((char)dropdownIndex) ); + #endif + // the switch replaces ax value + RCT2_CALLPROC_EBPSAFE(0x006BA9B5); // part of init audio*/ + + window_invalidate(w); + break; + case WIDX_TITLE_MUSIC_DROPDOWN: + if ((dropdownIndex == 1 || dropdownIndex == 3) && !platform_file_exists(get_file_path(PATH_ID_CSS50))) { + window_error_open(2742, 2743); + } + else { + gConfigSound.title_music = (sint8)dropdownIndex; + config_save_default(); + window_invalidate(w); + } + + stop_title_music(); + if (dropdownIndex != 0) + start_title_music(); + break; } break; - case WIDX_TEMPERATURE_DROPDOWN: - if (dropdownIndex != gGeneral_config.temperature_format) { - gGeneral_config.temperature_format = (sint8)dropdownIndex; - config_save(); - gfx_invalidate_screen(); + + case WINDOW_OPTIONS_PAGE_CONTROLS: + break; + + case WINDOW_OPTIONS_PAGE_MISC: + switch (widgetIndex) { + case WIDX_AUTOSAVE_DROPDOWN: + if (dropdownIndex != gConfigGeneral.autosave_frequency) { + gConfigGeneral.autosave_frequency = (uint8)dropdownIndex; + config_save_default(); + window_invalidate(w); + } + break; + case WIDX_TITLE_SEQUENCE_DROPDOWN: + if (dropdownIndex != gConfigGeneral.title_sequence) { + if (dropdownIndex == 0) gConfigGeneral.title_sequence = TITLE_SEQUENCE_RCT2; + else if (dropdownIndex == 1) gConfigGeneral.title_sequence = TITLE_SEQUENCE_OPENRCT2; + config_save_default(); + window_invalidate(w); + } + break; } break; - case WIDX_CONSTRUCTION_MARKER_DROPDOWN: - if (dropdownIndex != gGeneral_config.construction_marker_colour) { - gGeneral_config.construction_marker_colour = (uint8)dropdownIndex; - config_save(); - gfx_invalidate_screen(); - } - break; - case WIDX_LANGUAGE_DROPDOWN: - if (dropdownIndex != gCurrentLanguage - 1) { - language_open(dropdownIndex + 1); - gGeneral_config.language = dropdownIndex + 1; - config_save(); - gfx_invalidate_screen(); - } + + case WINDOW_OPTIONS_PAGE_TWITCH: break; } } /** -* +* * rct2: 0x006BAD48 */ static void window_options_invalidate() { rct_window *w; - int i; + rct_widget* widget; sint32 currentSoundDevice; window_get_register(w); + colour_scheme_update(w); - window_options_set_pressed_tab(w); - for (i = WIDX_RESOLUTION; i <= WIDX_SAVE_PLUGIN_DATA_CHECKBOX; i++) { - window_options_widgets[i].type = WWT_EMPTY; + if (window_options_page_widgets[w->page] != w->widgets) { + w->widgets = window_options_page_widgets[w->page]; + window_init_scroll_widgets(w); } + window_options_set_pressed_tab(w); + w->disabled_widgets = 0; switch (w->page) { case WINDOW_OPTIONS_PAGE_DISPLAY: - // resolution - RCT2_GLOBAL(0x013CE952 + 16, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_WIDTH, uint16); - RCT2_GLOBAL(0x013CE952 + 18, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_HEIGHT, uint16); - RCT2_GLOBAL(0x013CE952 + 12, uint16) = 2773 + gGeneral_config.fullscreen_mode; + RCT2_GLOBAL(0x013CE952 + 16, uint16) = (uint16)gConfigGeneral.fullscreen_width; + RCT2_GLOBAL(0x013CE952 + 18, uint16) = (uint16)gConfigGeneral.fullscreen_height; + RCT2_GLOBAL(0x013CE952 + 12, uint16) = 2773 + gConfigGeneral.fullscreen_mode; - // landscape tile smoothing checkbox - if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE)) - w->pressed_widgets &= ~(1ULL << WIDX_TILE_SMOOTHING_CHECKBOX); - else - w->pressed_widgets |= (1ULL << WIDX_TILE_SMOOTHING_CHECKBOX); + // disable resolution dropdown on "Fullscreen (desktop)" + if (gConfigGeneral.fullscreen_mode == 2){ + w->disabled_widgets |= (1 << WIDX_RESOLUTION_DROPDOWN); + w->disabled_widgets |= (1 << WIDX_RESOLUTION); + } + else { + w->disabled_widgets &= ~(1 << WIDX_RESOLUTION_DROPDOWN); + w->disabled_widgets &= ~(1 << WIDX_RESOLUTION); + } - // show gridlines checkbox - if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES)) - w->pressed_widgets |= (1ULL << WIDX_GRIDLINES_CHECKBOX); - else - w->pressed_widgets &= ~(1ULL << WIDX_GRIDLINES_CHECKBOX); + widget_set_checkbox_value(w, WIDX_TILE_SMOOTHING_CHECKBOX, (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE) == 0); + widget_set_checkbox_value(w, WIDX_GRIDLINES_CHECKBOX, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES); + widget_set_checkbox_value(w, WIDX_HARDWARE_DISPLAY_CHECKBOX, gConfigGeneral.hardware_display); // construction marker: celsius/fahrenheit - window_options_widgets[WIDX_CONSTRUCTION_MARKER].image = STR_WHITE + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8); + window_options_display_widgets[WIDX_CONSTRUCTION_MARKER].image = STR_WHITE + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8); - window_options_widgets[WIDX_RESOLUTION].type = WWT_DROPDOWN; - window_options_widgets[WIDX_RESOLUTION_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_FULLSCREEN].type = WWT_DROPDOWN; - window_options_widgets[WIDX_FULLSCREEN_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_TILE_SMOOTHING_CHECKBOX].type = WWT_CHECKBOX; - window_options_widgets[WIDX_GRIDLINES_CHECKBOX].type = WWT_CHECKBOX; - window_options_widgets[WIDX_CONSTRUCTION_MARKER].type = WWT_DROPDOWN; - window_options_widgets[WIDX_CONSTRUCTION_MARKER_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_display_widgets[WIDX_RESOLUTION].type = WWT_DROPDOWN; + window_options_display_widgets[WIDX_RESOLUTION_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_display_widgets[WIDX_FULLSCREEN].type = WWT_DROPDOWN; + window_options_display_widgets[WIDX_FULLSCREEN_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_display_widgets[WIDX_TILE_SMOOTHING_CHECKBOX].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_GRIDLINES_CHECKBOX].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_CONSTRUCTION_MARKER].type = WWT_DROPDOWN; + window_options_display_widgets[WIDX_CONSTRUCTION_MARKER_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_display_widgets[WIDX_HARDWARE_DISPLAY_CHECKBOX].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_THEMES].type = WWT_DROPDOWN; + window_options_display_widgets[WIDX_THEMES_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_display_widgets[WIDX_THEMES_BUTTON].type = WWT_DROPDOWN_BUTTON; break; + case WINDOW_OPTIONS_PAGE_CULTURE: // currency: pounds, dollars, etc. (10 total) - RCT2_GLOBAL(0x013CE952 + 12, uint16) = STR_POUNDS + gGeneral_config.currency_format; + RCT2_GLOBAL(0x013CE952 + 12, uint16) = STR_POUNDS + gConfigGeneral.currency_format; // distance: metric/imperial - RCT2_GLOBAL(0x013CE952 + 14, uint16) = STR_IMPERIAL + gGeneral_config.measurement_format; + RCT2_GLOBAL(0x013CE952 + 14, uint16) = STR_IMPERIAL + gConfigGeneral.measurement_format; // temperature: celsius/fahrenheit - RCT2_GLOBAL(0x013CE952 + 20, uint16) = STR_CELSIUS + gGeneral_config.temperature_format; + RCT2_GLOBAL(0x013CE952 + 20, uint16) = STR_CELSIUS + gConfigGeneral.temperature_format; // height: units/real values - RCT2_GLOBAL(0x013CE952 + 6, uint16) = gGeneral_config.show_height_as_units ? STR_UNITS : STR_REAL_VALUES; + RCT2_GLOBAL(0x013CE952 + 6, uint16) = gConfigGeneral.show_height_as_units ? STR_UNITS : STR_REAL_VALUES; - window_options_widgets[WIDX_LANGUAGE].type = WWT_DROPDOWN; - window_options_widgets[WIDX_LANGUAGE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_CURRENCY].type = WWT_DROPDOWN; - window_options_widgets[WIDX_CURRENCY_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_DISTANCE].type = WWT_DROPDOWN; - window_options_widgets[WIDX_DISTANCE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_TEMPERATURE].type = WWT_DROPDOWN; - window_options_widgets[WIDX_TEMPERATURE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_HEIGHT_LABELS].type = WWT_DROPDOWN; - window_options_widgets[WIDX_HEIGHT_LABELS_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_culture_widgets[WIDX_LANGUAGE].type = WWT_DROPDOWN; + window_options_culture_widgets[WIDX_LANGUAGE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_culture_widgets[WIDX_CURRENCY].type = WWT_DROPDOWN; + window_options_culture_widgets[WIDX_CURRENCY_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_culture_widgets[WIDX_DISTANCE].type = WWT_DROPDOWN; + window_options_culture_widgets[WIDX_DISTANCE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_culture_widgets[WIDX_TEMPERATURE].type = WWT_DROPDOWN; + window_options_culture_widgets[WIDX_TEMPERATURE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_culture_widgets[WIDX_HEIGHT_LABELS].type = WWT_DROPDOWN; + window_options_culture_widgets[WIDX_HEIGHT_LABELS_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_culture_widgets[WIDX_DATE_FORMAT].type = WWT_DROPDOWN; + window_options_culture_widgets[WIDX_DATE_FORMAT_DROPDOWN].type = WWT_DROPDOWN_BUTTON; break; + case WINDOW_OPTIONS_PAGE_AUDIO: currentSoundDevice = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32); // sound devices if (currentSoundDevice == -1 || gAudioDeviceCount == 0) { RCT2_GLOBAL(0x013CE952, uint16) = STR_SOUND_NONE; - } else { + } + else { RCT2_GLOBAL(0x013CE952, uint16) = 1170; RCT2_GLOBAL(0x013CE952 + 2, uint32) = (uint32)gAudioDevices[currentSoundDevice].name; } @@ -659,65 +1080,85 @@ static void window_options_invalidate() // music: on/off RCT2_GLOBAL(0x013CE952 + 8, uint16) = STR_OFF + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8); - // sound quality: low/medium/high - RCT2_GLOBAL(0x013CE952 + 10, uint16) = STR_SOUND_LOW + gSound_config.sound_quality; + widget_set_checkbox_value(w, WIDX_SOUND_CHECKBOX, gConfigSound.sound); + widget_set_checkbox_value(w, WIDX_MUSIC_CHECKBOX, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8)); - //Sound pause checkbox - if (!g_sounds_disabled) - w->pressed_widgets |= (1ULL << WIDX_SOUND_PAUSED_CHECKBOX); - else - w->pressed_widgets &= ~(1ULL << WIDX_SOUND_PAUSED_CHECKBOX); - - // sound software mixing buffer checkbox - if (gSound_config.forced_software_buffering) - w->pressed_widgets |= (1ULL << WIDX_SOUND_SW_BUFFER_CHECKBOX); - else - w->pressed_widgets &= ~(1ULL << WIDX_SOUND_SW_BUFFER_CHECKBOX); + if(w->frame_no == 0){ // initialize only on first frame, otherwise the scrollbars wont be able to be modified + widget = &window_options_audio_widgets[WIDX_MASTER_VOLUME]; + w->scrolls[0].h_left = (sint16)ceil((gConfigSound.master_volume / 100.0f) * (w->scrolls[0].h_right - ((widget->right - widget->left) - 1))); + widget = &window_options_audio_widgets[WIDX_MUSIC_VOLUME]; + w->scrolls[1].h_left = (sint16)ceil((gConfigSound.music_volume / 100.0f) * (w->scrolls[1].h_right - ((widget->right - widget->left) - 1))); + } - window_options_widgets[WIDX_SOUND].type = WWT_DROPDOWN; - window_options_widgets[WIDX_SOUND_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_MUSIC].type = WWT_DROPDOWN; - window_options_widgets[WIDX_MUSIC_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_SOUND_QUALITY].type = WWT_DROPDOWN; - window_options_widgets[WIDX_SOUND_QUALITY_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_options_widgets[WIDX_SOUND_SW_BUFFER_CHECKBOX].type = WWT_CHECKBOX; - window_options_widgets[WIDX_SOUND_PAUSED_CHECKBOX].type = WWT_CHECKBOX; + widget_scroll_update_thumbs(w, WIDX_MASTER_VOLUME); + widget_scroll_update_thumbs(w, WIDX_MUSIC_VOLUME); + + window_options_audio_widgets[WIDX_SOUND].type = WWT_DROPDOWN; + window_options_audio_widgets[WIDX_SOUND_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_audio_widgets[WIDX_SOUND_CHECKBOX].type = WWT_CHECKBOX; + window_options_audio_widgets[WIDX_MUSIC_CHECKBOX].type = WWT_CHECKBOX; + window_options_audio_widgets[WIDX_TITLE_MUSIC].type = WWT_DROPDOWN; + window_options_audio_widgets[WIDX_TITLE_MUSIC_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_audio_widgets[WIDX_MASTER_VOLUME].type = WWT_SCROLL; + window_options_audio_widgets[WIDX_MUSIC_VOLUME].type = WWT_SCROLL; break; - case WINDOW_OPTIONS_PAGE_INPUT: - // screen edge scrolling checkbox - if (gGeneral_config.edge_scrolling) - w->pressed_widgets |= (1ULL << WIDX_SCREEN_EDGE_SCROLLING); - else - w->pressed_widgets &= ~(1ULL << WIDX_SCREEN_EDGE_SCROLLING); - window_options_widgets[WIDX_SCREEN_EDGE_SCROLLING].type = WWT_CHECKBOX; - window_options_widgets[WIDX_HOTKEY_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + case WINDOW_OPTIONS_PAGE_CONTROLS: + widget_set_checkbox_value(w, WIDX_SCREEN_EDGE_SCROLLING, gConfigGeneral.edge_scrolling); + widget_set_checkbox_value(w, WIDX_TOOLBAR_SHOW_FINANCES, gConfigInterface.toolbar_show_finances); + widget_set_checkbox_value(w, WIDX_TOOLBAR_SHOW_RESEARCH, gConfigInterface.toolbar_show_research); + widget_set_checkbox_value(w, WIDX_TOOLBAR_SHOW_CHEATS, gConfigInterface.toolbar_show_cheats); + + window_options_controls_widgets[WIDX_SCREEN_EDGE_SCROLLING].type = WWT_CHECKBOX; + window_options_controls_widgets[WIDX_HOTKEY_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_controls_widgets[WIDX_TOOLBAR_SHOW_FINANCES].type = WWT_CHECKBOX; + window_options_controls_widgets[WIDX_TOOLBAR_SHOW_RESEARCH].type = WWT_CHECKBOX; + window_options_controls_widgets[WIDX_TOOLBAR_SHOW_CHEATS].type = WWT_CHECKBOX; break; + case WINDOW_OPTIONS_PAGE_MISC: - // real name checkbox - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES) - w->pressed_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX); - else - w->pressed_widgets &= ~(1ULL << WIDX_REAL_NAME_CHECKBOX); - - // save plugin data checkbox - if (gGeneral_config.save_plugin_data) - w->pressed_widgets |= (1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX); - else - w->pressed_widgets &= ~(1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX); - // unknown park flag can disable real name checkbox if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x8000) w->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX); // save plugin data checkbox: visible or not - if (RCT2_GLOBAL(0x00F42BDA, uint8) == 1) - window_options_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_EMPTY; + if (RCT2_GLOBAL(RCT2_ADDRESS_CUSTOM_OBJECTS_INSTALLED, uint8) == 1) + window_options_misc_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_EMPTY; else - window_options_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX; - window_options_widgets[WIDX_REAL_NAME_CHECKBOX].type = WWT_CHECKBOX; - window_options_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX; + widget_set_checkbox_value(w, WIDX_ALLOW_SUBTYPE_SWITCHING, gConfigInterface.allow_subtype_switching); + widget_set_checkbox_value(w, WIDX_REAL_NAME_CHECKBOX, RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES); + widget_set_checkbox_value(w, WIDX_SAVE_PLUGIN_DATA_CHECKBOX, gConfigGeneral.save_plugin_data); + widget_set_checkbox_value(w, WIDX_TEST_UNFINISHED_TRACKS, gConfigGeneral.test_unfinished_tracks); + widget_set_checkbox_value(w, WIDX_AUTO_STAFF_PLACEMENT, gConfigGeneral.auto_staff_placement); + widget_set_checkbox_value(w, WIDX_DEBUGGING_TOOLS, gConfigGeneral.debugging_tools); + + window_options_misc_widgets[WIDX_REAL_NAME_CHECKBOX].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_AUTOSAVE].type = WWT_DROPDOWN; + window_options_misc_widgets[WIDX_AUTOSAVE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_misc_widgets[WIDX_ALLOW_SUBTYPE_SWITCHING].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_TEST_UNFINISHED_TRACKS].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_AUTO_STAFF_PLACEMENT].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_DEBUGGING_TOOLS].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].type = WWT_DROPDOWN; + window_options_misc_widgets[WIDX_TITLE_SEQUENCE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + break; + + case WINDOW_OPTIONS_PAGE_TWITCH: + widget_set_checkbox_value(w, WIDX_FOLLOWER_PEEP_NAMES_CHECKBOX, gConfigTwitch.enable_follower_peep_names); + widget_set_checkbox_value(w, WIDX_FOLLOWER_PEEP_TRACKING_CHECKBOX, gConfigTwitch.enable_follower_peep_tracking); + widget_set_checkbox_value(w, WIDX_CHAT_PEEP_NAMES_CHECKBOX, gConfigTwitch.enable_chat_peep_names); + widget_set_checkbox_value(w, WIDX_CHAT_PEEP_TRACKING_CHECKBOX, gConfigTwitch.enable_chat_peep_tracking); + widget_set_checkbox_value(w, WIDX_NEWS_CHECKBOX, gConfigTwitch.enable_news); + + window_options_twitch_widgets[WIDX_CHANNEL_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_options_twitch_widgets[WIDX_FOLLOWER_PEEP_NAMES_CHECKBOX].type = WWT_CHECKBOX; + window_options_twitch_widgets[WIDX_FOLLOWER_PEEP_TRACKING_CHECKBOX].type = WWT_CHECKBOX; + window_options_twitch_widgets[WIDX_CHAT_PEEP_NAMES_CHECKBOX].type = WWT_CHECKBOX; + window_options_twitch_widgets[WIDX_CHAT_PEEP_TRACKING_CHECKBOX].type = WWT_CHECKBOX; + window_options_twitch_widgets[WIDX_NEWS_CHECKBOX].type = WWT_CHECKBOX; break; } } @@ -727,6 +1168,24 @@ static void window_options_update(rct_window *w) // Tab animation w->frame_no++; widget_invalidate(w, WIDX_TAB_1 + w->page); + + rct_widget *widget; + if (w->page == WINDOW_OPTIONS_PAGE_AUDIO) { + widget = &window_options_audio_widgets[WIDX_MASTER_VOLUME]; + uint8 master_volume = (uint8)(((float)w->scrolls[0].h_left / (w->scrolls[0].h_right - ((widget->right - widget->left) - 1))) * 100); + widget = &window_options_audio_widgets[WIDX_MUSIC_VOLUME]; + uint8 music_volume = (uint8)(((float)w->scrolls[1].h_left / (w->scrolls[1].h_right - ((widget->right - widget->left) - 1))) * 100); + if (master_volume != gConfigSound.master_volume) { + gConfigSound.master_volume = master_volume; + config_save_default(); + } + if (music_volume != gConfigSound.music_volume) { + gConfigSound.music_volume = music_volume; + config_save_default(); + } + widget_invalidate(w, WIDX_MASTER_VOLUME); + widget_invalidate(w, WIDX_MUSIC_VOLUME); + } } /** @@ -737,7 +1196,6 @@ static void window_options_paint() { rct_window *w; rct_drawpixelinfo *dpi; - char buffer[256]; window_paint_get_registers(w, dpi); @@ -746,31 +1204,77 @@ static void window_options_paint() switch (w->page) { case WINDOW_OPTIONS_PAGE_DISPLAY: - gfx_draw_string_left(dpi, STR_DISPLAY_RESOLUTION, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_RESOLUTION].top + 1); + gfx_draw_string_left(dpi, STR_DISPLAY_RESOLUTION, w, w->colours[1], w->x + 10, w->y + window_options_display_widgets[WIDX_RESOLUTION].top + 1); + gfx_draw_string_left(dpi, STR_FULLSCREEN_MODE, w, w->colours[1], w->x + 10, w->y + window_options_display_widgets[WIDX_FULLSCREEN].top + 1); + gfx_draw_string_left(dpi, STR_CONSTRUCTION_MARKER, w, w->colours[1], w->x + 10, w->y + window_options_display_widgets[WIDX_CONSTRUCTION_MARKER].top + 1); - sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Fullscreen mode:"); - gfx_draw_string(dpi, buffer, 0, w->x + 10, w->y + window_options_widgets[WIDX_FULLSCREEN].top + 1); - - gfx_draw_string_left(dpi, STR_CONSTRUCTION_MARKER, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_CONSTRUCTION_MARKER].top + 1); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigThemes.presets[gCurrentTheme].name; + gfx_draw_string_left(dpi, 5238, NULL, w->colours[1], w->x + 10, w->y + window_options_display_widgets[WIDX_THEMES].top + 1); + gfx_draw_string_left_clipped( + dpi, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, + w->colours[1], + w->x + window_options_display_widgets[WIDX_THEMES].left + 1, + w->y + window_options_display_widgets[WIDX_THEMES].top, + window_options_display_widgets[WIDX_THEMES_DROPDOWN].left - window_options_display_widgets[WIDX_THEMES].left - 4 + ); break; case WINDOW_OPTIONS_PAGE_CULTURE: - gfx_draw_string_left(dpi, 2776, w, 12, w->x + 10, w->y + window_options_widgets[WIDX_LANGUAGE].top + 1); + gfx_draw_string_left(dpi, 2776, w, w->colours[1], w->x + 10, w->y + window_options_culture_widgets[WIDX_LANGUAGE].top + 1); gfx_draw_string( dpi, (char*)language_names[gCurrentLanguage], - 12, - w->x + window_options_widgets[WIDX_LANGUAGE].left + 1, - w->y + window_options_widgets[WIDX_LANGUAGE].top + w->colours[1], + w->x + window_options_culture_widgets[WIDX_LANGUAGE].left + 1, + w->y + window_options_culture_widgets[WIDX_LANGUAGE].top ); - gfx_draw_string_left(dpi, STR_CURRENCY, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_CURRENCY].top + 1); - gfx_draw_string_left(dpi, STR_DISTANCE_AND_SPEED, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_DISTANCE].top + 1); - gfx_draw_string_left(dpi, STR_TEMPERATURE, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_TEMPERATURE].top + 1); - gfx_draw_string_left(dpi, STR_HEIGHT_LABELS, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_HEIGHT_LABELS].top + 1); + gfx_draw_string_left(dpi, STR_CURRENCY, w, w->colours[1], w->x + 10, w->y + window_options_culture_widgets[WIDX_CURRENCY].top + 1); + gfx_draw_string_left(dpi, STR_DISTANCE_AND_SPEED, w, w->colours[1], w->x + 10, w->y + window_options_culture_widgets[WIDX_DISTANCE].top + 1); + gfx_draw_string_left(dpi, STR_TEMPERATURE, w, w->colours[1], w->x + 10, w->y + window_options_culture_widgets[WIDX_TEMPERATURE].top + 1); + gfx_draw_string_left(dpi, STR_HEIGHT_LABELS, w, w->colours[1], w->x + 10, w->y + window_options_culture_widgets[WIDX_HEIGHT_LABELS].top + 1); + gfx_draw_string_left(dpi, 5161, w, w->colours[1], w->x + 10, w->y + window_options_culture_widgets[WIDX_DATE_FORMAT].top + 1); + gfx_draw_string_left( + dpi, + 5162 + gConfigGeneral.date_format, + NULL, + w->colours[1], + w->x + window_options_culture_widgets[WIDX_DATE_FORMAT].left + 1, + w->y + window_options_culture_widgets[WIDX_DATE_FORMAT].top + ); break; case WINDOW_OPTIONS_PAGE_AUDIO: - gfx_draw_string_left(dpi, STR_MUSIC, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_MUSIC].top + 1); - gfx_draw_string_left(dpi, STR_SOUND_QUALITY, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_SOUND_QUALITY].top + 1); + gfx_draw_string_left(dpi, 2738, w, w->colours[1], w->x + 10, w->y + window_options_audio_widgets[WIDX_TITLE_MUSIC].top + 1); + gfx_draw_string_left( + dpi, + (gConfigSound.title_music == 3 ? 5126 : 2739 + gConfigSound.title_music), + NULL, + w->colours[1], + w->x + window_options_audio_widgets[WIDX_TITLE_MUSIC].left + 1, + w->y + window_options_audio_widgets[WIDX_TITLE_MUSIC].top + ); + break; + case WINDOW_OPTIONS_PAGE_MISC: + gfx_draw_string_left(dpi, 2700, w, w->colours[1], w->x + 10, w->y + window_options_misc_widgets[WIDX_AUTOSAVE].top + 1); + gfx_draw_string_left( + dpi, + 2701 + gConfigGeneral.autosave_frequency, + NULL, + w->colours[1], + w->x + window_options_misc_widgets[WIDX_AUTOSAVE].left + 1, + w->y + window_options_misc_widgets[WIDX_AUTOSAVE].top + ); + + gfx_draw_string_left(dpi, STR_TITLE_SEQUENCE, w, w->colours[1], w->x + 10, w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top + 1); + gfx_draw_string_left( + dpi, + STR_TITLE_SEQUENCE_RCT1 + gConfigGeneral.title_sequence, + NULL, + w->colours[1], + w->x + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].left + 1, + w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top + ); break; } } @@ -783,7 +1287,7 @@ static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int w->y + widget->top, widget->bottom - widget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, num_items, widget->right - widget->left - 3 ); @@ -791,24 +1295,59 @@ static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int static void window_options_update_height_markers() { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, uint16) = gGeneral_config.show_height_as_units ? - 0 : (gGeneral_config.show_height_as_units + 1) * 256; - config_save(); + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, uint16) = gConfigGeneral.show_height_as_units ? + 0 : (gConfigGeneral.measurement_format + 1) * 256; + config_save_default(); gfx_invalidate_screen(); } +static void window_options_scrollgetsize() +{ + rct_window *w; + short scrollIndex; + + window_scroll_get_registers(w, scrollIndex); + + if (w->page == WINDOW_OPTIONS_PAGE_AUDIO) { + int width = 1000; + int height = 0; + window_scrollsize_set_registers(width, height); + } +} + +static void window_options_text_input(){ + short widgetIndex; + rct_window *w; + char _cl; + char* text; + + window_text_input_get_registers(w, widgetIndex, _cl, text); + if (_cl == 0) + { + return; + } + + if (widgetIndex == WIDX_CHANNEL_BUTTON){ + if (gConfigTwitch.channel != NULL) + free(gConfigTwitch.channel); + gConfigTwitch.channel = _strdup(text); + config_save_default(); + } +} + #pragma region Common static void window_options_set_page(rct_window *w, int page) { w->page = page; w->frame_no = 0; + w->enabled_widgets = window_options_page_enabled_widgets[page]; + w->pressed_widgets = 0; + w->widgets = window_options_page_widgets[page]; window_invalidate(w); - - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); - + window_event_resize_call(w); + window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); } @@ -840,8 +1379,9 @@ static void window_options_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_DISPLAY, 5442); window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_CULTURE, 5229); window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_AUDIO, 5335); - window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_INPUT, 5201); + window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_CONTROLS, 5201); window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_MISC, 5205); + window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_TWITCH, SPR_G2_TAB_TWITCH); } -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/windows/park.c b/src/windows/park.c index 19fe4eb853..1fe32e1dcb 100644 --- a/src/windows/park.c +++ b/src/windows/park.c @@ -36,7 +36,9 @@ #include "../util/util.h" #include "../world/park.h" #include "../world/sprite.h" +#include "../management/finance.h" #include "dropdown.h" +#include "../interface/themes.h" enum WINDOW_PARK_PAGE { WINDOW_PARK_PAGE_ENTRANCE, @@ -65,9 +67,11 @@ enum WINDOW_PARK_WIDGET_IDX { WIDX_STATUS, WIDX_OPEN_OR_CLOSE, WIDX_BUY_LAND_RIGHTS, - WIDX_BUY_CONSTRUCTION_RIGHTS, + //WIDX_BUY_CONSTRUCTION_RIGHTS, WIDX_LOCATE, WIDX_RENAME, + WIDX_CLOSE_LIGHT, + WIDX_OPEN_LIGHT, WIDX__ = 11, WIDX_PRICE, @@ -79,73 +83,45 @@ enum WINDOW_PARK_WIDGET_IDX { #pragma region Widgets -static rct_widget window_park_entrance_widgets[] = { - { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_RESIZE, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, // tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, // tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, // tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, // tab 6 - { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP }, // tab 7 +#define MAIN_PARK_WIDGETS \ + { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, /* panel / background */ \ + { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, /* title bar */ \ + { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, /* close x button */ \ + { WWT_RESIZE, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, /* tab content panel */ \ + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, /* tab 1 */ \ + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, /* tab 2 */ \ + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, /* tab 3 */ \ + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, /* tab 4 */ \ + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, /* tab 5 */ \ + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, /* tab 6 */ \ + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP } /* tab 7 */ +static rct_widget window_park_entrance_widgets[] = { + MAIN_PARK_WIDGETS, { WWT_VIEWPORT, 1, 3, 204, 46, 160, 0x0FFFFFFFF, STR_NONE }, // viewport { WWT_12, 1, 3, 204, 161, 171, 0x0FFFFFFFF, STR_NONE }, // status { WWT_FLATBTN, 1, 205, 228, 49, 72, 0x0FFFFFFFF, STR_OPEN_OR_CLOSE_PARK_TIP }, // open / close - { WWT_FLATBTN, 1, 205, 228, 73, 96, SPR_BUY_LAND_RIGHTS, SPR_BUY_LAND_RIGHTS_TIP }, // buy land rights - { WWT_FLATBTN, 1, 205, 228, 97, 120, SPR_BUY_CONSTRUCTION_RIGHTS, SPR_BUY_CONSTRUCTION_RIGHTS_TIP }, // buy construction rights - { WWT_FLATBTN, 1, 205, 228, 121, 144, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, // locate - { WWT_FLATBTN, 1, 205, 228, 145, 168, SPR_RENAME, STR_NAME_PARK_TIP }, // rename + { WWT_FLATBTN, 1, 205, 228, 73, 96, SPR_BUY_LAND_RIGHTS, 5135 }, // buy land rights + //{ WWT_FLATBTN, 1, 205, 228, 97, 120, SPR_BUY_CONSTRUCTION_RIGHTS, SPR_BUY_CONSTRUCTION_RIGHTS_TIP }, // buy construction rights + { WWT_FLATBTN, 1, 205, 228, 97, 120, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, // locate + { WWT_FLATBTN, 1, 205, 228, 121, 144, SPR_RENAME, STR_NAME_PARK_TIP }, // rename + { WWT_IMGBTN, 1, 210, 223, 51, 65, SPR_G2_RCT1_CLOSE_BUTTON_0, 5296 }, + { WWT_IMGBTN, 1, 210, 223, 66, 79, SPR_G2_RCT1_OPEN_BUTTON_0, 5297 }, { WIDGETS_END }, }; static rct_widget window_park_rating_widgets[] = { - { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, // tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, // tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, // tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, // tab 6 - { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP }, // tab 7 + MAIN_PARK_WIDGETS, { WIDGETS_END }, }; static rct_widget window_park_guests_widgets[] = { - { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, // tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, // tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, // tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, // tab 6 - { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP }, // tab 7 + MAIN_PARK_WIDGETS, { WIDGETS_END }, }; static rct_widget window_park_price_widgets[] = { - { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, // tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, // tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, // tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, // tab 6 - { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP }, // tab 7 - - + MAIN_PARK_WIDGETS, { WWT_24, 1, 7, 146, 50, 61, STR_ADMISSION_PRICE, STR_NONE }, // { WWT_SPINNER, 1, 147, 222, 50, 61, 0x595, STR_NONE }, // price { WWT_DROPDOWN_BUTTON, 1, 211, 221, 51, 55, STR_NUMERIC_UP, STR_NONE }, // increase price @@ -154,49 +130,18 @@ static rct_widget window_park_price_widgets[] = { }; static rct_widget window_park_stats_widgets[] = { - { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, // tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, // tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, // tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, // tab 6 - { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP }, // tab 7 + MAIN_PARK_WIDGETS, { WIDGETS_END }, }; static rct_widget window_park_objective_widgets[] = { - { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, // tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, // tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, // tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, // tab 6 - { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP }, // tab 7 - + MAIN_PARK_WIDGETS, { WWT_DROPDOWN_BUTTON, 1, 7, 222, 209, 220, STR_ENTER_NAME_INTO_SCENARIO_CHART, STR_NONE }, // enter name { WIDGETS_END }, }; static rct_widget window_park_awards_widgets[] = { - { WWT_FRAME, 0, 0, 229, 0, 223, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 228, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 217, 227, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, 229, 43, 173, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_PARK_ENTRANCE_TAB_TIP }, // tab 1 - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_PARK_RATING_TAB_TIP }, // tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_PARK_GUESTS_TAB_TIP }, // tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_PARK_PRICE_TAB_TIP }, // tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_PARK_STATS_TAB_TIP }, // tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_PARK_OBJECTIVE_TAB_TIP }, // tab 6 - { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_PARK_AWARDS_TAB_TIP }, // tab 7 + MAIN_PARK_WIDGETS, { WIDGETS_END }, }; @@ -229,6 +174,7 @@ static void window_park_entrance_toolabort(); static void window_park_entrance_textinput(); static void window_park_entrance_invalidate(); static void window_park_entrance_paint(); +void toggle_land_rights_window(rct_window *parkWindow, int widgetIndex); static void window_park_rating_mouseup(); static void window_park_rating_resize(); @@ -510,9 +456,11 @@ static uint32 window_park_page_enabled_widgets[] = { (1 << WIDX_TAB_7) | (1 << WIDX_OPEN_OR_CLOSE) | (1 << WIDX_BUY_LAND_RIGHTS) | - (1 << WIDX_BUY_CONSTRUCTION_RIGHTS) | + //(1 << WIDX_BUY_CONSTRUCTION_RIGHTS) | (1 << WIDX_LOCATE) | - (1 << WIDX_RENAME), + (1 << WIDX_RENAME) | + (1 << WIDX_CLOSE_LIGHT) | + (1 << WIDX_OPEN_LIGHT), (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | @@ -572,6 +520,19 @@ static uint32 window_park_page_enabled_widgets[] = { (1 << WIDX_TAB_7) }; +static uint32 window_park_page_hold_down_widgets[] = { + 0, + 0, + 0, + + (1 << WIDX_INCREASE_PRICE) | + (1 << WIDX_DECREASE_PRICE), + + 0, + 0, + 0 +}; + #pragma endregion static void window_park_init_viewport(rct_window *w); @@ -589,7 +550,7 @@ rct_window *window_park_open() { rct_window* w; - w = window_create_auto_pos(230, 174, (uint32*)window_park_entrance_events, WC_PARK_INFORMATION, 0x0400); + w = window_create_auto_pos(230, 174 + 9, (uint32*)window_park_entrance_events, WC_PARK_INFORMATION, WF_10); w->widgets = window_park_entrance_widgets; w->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_ENTRANCE]; w->number = 0; @@ -600,9 +561,6 @@ rct_window *window_park_open() w->var_48C = -1; w->var_492 = 0; window_park_set_disabled_tabs(w); - w->colours[0] = 1; - w->colours[1] = 19; - w->colours[2] = 19; return w; } @@ -611,12 +569,18 @@ rct_window *window_park_open() * * rct2: 0x00667F8B */ -void window_park_set_disabled_tabs(rct_window *w) +static void window_park_set_disabled_tabs(rct_window *w) { // Disable price tab if money is disabled w->disabled_widgets = (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? (1 << WIDX_TAB_4) : 0; } +static void window_park_prepare_window_title_text() +{ + RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); +} + #pragma region Entrance page /** @@ -684,17 +648,22 @@ static void window_park_entrance_mouseup() window_park_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_BUY_LAND_RIGHTS: - RCT2_CALLPROC_X(0x006682F7, 0, 0, 0, widgetIndex, (int)w, 0, 0); - break; - case WIDX_BUY_CONSTRUCTION_RIGHTS: - RCT2_CALLPROC_X(0x00668393, 0, 0, 0, widgetIndex, (int)w, 0, 0); + toggle_land_rights_window(w, WIDX_BUY_LAND_RIGHTS); break; + // case WIDX_BUY_CONSTRUCTION_RIGHTS: + // break; case WIDX_LOCATE: window_scroll_to_viewport(w); break; case WIDX_RENAME: RCT2_GLOBAL(0x013CE962, uint32) = RCT2_GLOBAL(0x013573D8, uint32); - window_text_input_open(w, WIDX_RENAME, STR_PARK_NAME, STR_ENTER_PARK_NAME, RCT2_GLOBAL(0x013573D4, rct_string_id), 0); + window_text_input_open(w, WIDX_RENAME, STR_PARK_NAME, STR_ENTER_PARK_NAME, RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id), 0, 32); + break; + case WIDX_CLOSE_LIGHT: + park_set_open(0); + break; + case WIDX_OPEN_LIGHT: + park_set_open(1); break; } } @@ -755,19 +724,17 @@ static void window_park_entrance_dropdown() window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex == WIDX_OPEN_OR_CLOSE) { if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + if (dropdownIndex != 0) { - dropdownIndex &= 0x00FF; - dropdownIndex |= 0x0100; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1724; + park_set_open(1); } else { - dropdownIndex &= 0x00FF; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1723; + park_set_open(0); } - game_do_command(0, 1, 0, dropdownIndex, GAME_COMMAND_SET_PARK_OPEN, 0, 0); } } @@ -781,6 +748,84 @@ static void window_park_entrance_update(rct_window *w) widget_invalidate(w, WIDX_TAB_1); } + +void window_park_entrance_tool_update_land_rights(sint16 x, sint16 y){ + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + + rct_xy16 mapTile = { 0 }; + sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + + if (mapTile.x == (sint16)0x8000){ + if (RCT2_GLOBAL(0x00F1AD62, money32) != MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F1AD62, money32) = MONEY32_UNDEFINED; + window_invalidate_by_class(WC_CLEAR_SCENERY); + } + return; + } + + uint8 state_changed = 0; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != 4){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + state_changed++; + } + + sint16 tool_size = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + if (tool_size == 0) + tool_size = 1; + + sint16 tool_length = (tool_size - 1) * 32; + + // Move to tool bottom left + mapTile.x -= (tool_size - 1) * 16; + mapTile.y -= (tool_size - 1) * 16; + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + state_changed++; + } + + mapTile.x += tool_length; + mapTile.y += tool_length; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + state_changed++; + } + + map_invalidate_selection_rect(); + if (!state_changed) + return; + + RCT2_GLOBAL(0x00F1AD62, uint32) = game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 0x4, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + LandRightsMode ? 0x00E : 0x20F, + 35, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); +} + /** * * rct2: 0x006681D1 @@ -792,19 +837,10 @@ static void window_park_entrance_toolupdate() window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_BUY_LAND_RIGHTS) { - RCT2_CALLPROC_X(0x0068AAE1, x, y, 0, 0, (int)w, 0, 0); - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= 0xFFFE; - screen_pos_to_map_pos(&x, &y); - if (x != SPRITE_LOCATION_NULL) { - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = y; - RCT2_CALLPROC_X(0x0068AAE1, x, y, 0, 0, (int)w, 0, 0); - } + switch (widgetIndex){ + case WIDX_BUY_LAND_RIGHTS: + window_park_entrance_tool_update_land_rights(x, y); + break; } } @@ -819,7 +855,38 @@ static void window_park_entrance_tooldown() window_tool_get_registers(w, widgetIndex, x, y); - RCT2_CALLPROC_X(0x006681E6, x, y, 0, widgetIndex, (int)w, 0, 0); + switch (widgetIndex){ + case WIDX_BUY_LAND_RIGHTS: + if (LandRightsMode) { + if (x != (sint16)0x8000) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 0x6BD; // Can't buy land... + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + 0x00E, + GAME_COMMAND_BUY_LAND_RIGHTS, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + } + } + else { + if (x != (sint16)0x8000) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 0x6C0; // Can't buy construction rights here... + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + 0x20F, + GAME_COMMAND_BUY_LAND_RIGHTS, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + } + } + break; + } } /** @@ -833,7 +900,42 @@ static void window_park_entrance_tooldrag() window_tool_get_registers(w, widgetIndex, x, y); - RCT2_CALLPROC_X(0x006681FB, x, y, 0, widgetIndex, (int)w, 0, 0); + rct_window* w2 = window_find_by_number(0xB, 0); + + if (!w2) { + switch (widgetIndex){ + case WIDX_BUY_LAND_RIGHTS: + if (LandRightsMode) { + if (x != (sint16)0x8000) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 0x6BD; // Can't buy land... + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + 0x00E, + GAME_COMMAND_BUY_LAND_RIGHTS, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + } + } + else { + if (x != (sint16)0x8000) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 0x6C0; // Can't buy construction rights here... + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + 0x20F, + GAME_COMMAND_BUY_LAND_RIGHTS, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + } + } + break; + } + } } /** @@ -849,11 +951,15 @@ static void window_park_entrance_toolabort() if (widgetIndex == WIDX_BUY_LAND_RIGHTS) { hide_gridlines(); - hide_land_rights(); - } else if (widgetIndex == WIDX_BUY_CONSTRUCTION_RIGHTS) { - hide_gridlines(); - hide_construction_rights(); - } + if (LandRightsMode) + hide_land_rights(); + else + hide_construction_rights(); + } + //else if (widgetIndex == WIDX_BUY_CONSTRUCTION_RIGHTS) { + // hide_gridlines(); + // hide_construction_rights(); + //} } /** @@ -869,14 +975,8 @@ static void window_park_entrance_textinput() window_textinput_get_registers(w, widgetIndex, result, text); - if (widgetIndex == WIDX_RENAME) { - if (result) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_RENAME_PARK; - game_do_command(1, 1, 0, *((int*)(text + 0)), GAME_COMMAND_33, *((int*)(text + 8)), *((int*)(text + 4))); - game_do_command(2, 1, 0, *((int*)(text + 12)), GAME_COMMAND_33, *((int*)(text + 20)), *((int*)(text + 16))); - game_do_command(0, 1, 0, *((int*)(text + 24)), GAME_COMMAND_33, *((int*)(text + 32)), *((int*)(text + 28))); - } - } + if (widgetIndex == WIDX_RENAME && result) + park_set_name(text); } /** @@ -885,10 +985,11 @@ static void window_park_entrance_textinput() */ static void window_park_entrance_invalidate() { - int i; + int i, height; rct_window *w; window_get_register(w); + colour_scheme_update(w); w->widgets = window_park_page_widgets[w->page]; window_init_scroll_widgets(w); @@ -896,13 +997,25 @@ static void window_park_entrance_invalidate() window_park_set_pressed_tab(w); // Set open / close park button state - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); window_park_entrance_widgets[WIDX_OPEN_OR_CLOSE].image = park_is_open() ? SPR_OPEN : SPR_CLOSED; + window_park_entrance_widgets[WIDX_CLOSE_LIGHT].image = SPR_G2_RCT1_CLOSE_BUTTON_0 + !park_is_open() * 2 + widget_is_pressed(w, WIDX_CLOSE_LIGHT); + window_park_entrance_widgets[WIDX_OPEN_LIGHT].image = SPR_G2_RCT1_OPEN_BUTTON_0 + park_is_open() * 2 + widget_is_pressed(w, WIDX_OPEN_LIGHT); // Only allow closing of park for guest / rating objective - if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_GUESTS_AND_RATING) - w->disabled_widgets |= (1 << WIDX_OPEN_OR_CLOSE); + // Only allow closing of park when there is money + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_GUESTS_AND_RATING || + (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) + w->disabled_widgets |= (1 << WIDX_OPEN_OR_CLOSE) | (1 << WIDX_CLOSE_LIGHT) | (1 << WIDX_OPEN_LIGHT); + else + w->disabled_widgets &= ~((1 << WIDX_OPEN_OR_CLOSE) | (1 << WIDX_CLOSE_LIGHT) | (1 << WIDX_OPEN_LIGHT)); + + // Only allow purchase of land when there is money + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) + window_park_entrance_widgets[WIDX_BUY_LAND_RIGHTS].type = WWT_EMPTY; + else + window_park_entrance_widgets[WIDX_BUY_LAND_RIGHTS].type = WWT_FLATBTN; window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_7); window_park_anchor_border_widgets(w); @@ -913,20 +1026,39 @@ static void window_park_entrance_invalidate() window_park_entrance_widgets[WIDX_STATUS].right = w->width - 26; window_park_entrance_widgets[WIDX_STATUS].top = w->height - 13; window_park_entrance_widgets[WIDX_STATUS].bottom = w->height - 3; - for (i = WIDX_OPEN_OR_CLOSE; i <= WIDX_RENAME; i++) { - window_park_entrance_widgets[i].left = w->width - 25; - window_park_entrance_widgets[i].right = w->width - 2; + + if (theme_get_preset()->features.rct1_park_lights) { + window_park_entrance_widgets[WIDX_OPEN_OR_CLOSE].type = WWT_EMPTY; + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_GUESTS_AND_RATING) { + window_park_entrance_widgets[WIDX_CLOSE_LIGHT].type = WWT_FLATBTN; + window_park_entrance_widgets[WIDX_OPEN_LIGHT].type = WWT_FLATBTN; + } + else { + window_park_entrance_widgets[WIDX_CLOSE_LIGHT].type = WWT_IMGBTN; + window_park_entrance_widgets[WIDX_OPEN_LIGHT].type = WWT_IMGBTN; + } + height = window_park_entrance_widgets[WIDX_OPEN_LIGHT].bottom + 5; + } + else { + window_park_entrance_widgets[WIDX_OPEN_OR_CLOSE].type = WWT_FLATBTN; + window_park_entrance_widgets[WIDX_CLOSE_LIGHT].type = WWT_EMPTY; + window_park_entrance_widgets[WIDX_OPEN_LIGHT].type = WWT_EMPTY; + height = 49; } - // Only allow closing of park and purchase of land when there is money - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) { - window_park_entrance_widgets[WIDX_OPEN_OR_CLOSE].type = WWT_EMPTY; - window_park_entrance_widgets[WIDX_BUY_LAND_RIGHTS].type = WWT_EMPTY; - window_park_entrance_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].type = WWT_EMPTY; - } else { - window_park_entrance_widgets[WIDX_OPEN_OR_CLOSE].type = WWT_FLATBTN; - window_park_entrance_widgets[WIDX_BUY_LAND_RIGHTS].type = WWT_FLATBTN; - window_park_entrance_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].type = WWT_FLATBTN; + for (i = WIDX_CLOSE_LIGHT; i <= WIDX_OPEN_LIGHT; i++) { + window_park_entrance_widgets[i].left = w->width - 20; + window_park_entrance_widgets[i].right = w->width - 7; + } + for (i = WIDX_OPEN_OR_CLOSE; i <= WIDX_RENAME; i++) { + if (window_park_entrance_widgets[i].type == WWT_EMPTY) + continue; + + window_park_entrance_widgets[i].left = w->width - 25; + window_park_entrance_widgets[i].right = w->width - 2; + window_park_entrance_widgets[i].top = height; + window_park_entrance_widgets[i].bottom = height + 23; + height += 24; } } @@ -1007,7 +1139,7 @@ static void window_park_init_viewport(rct_window *w) } // Call invalidate event - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); w->viewport_focus_coordinates.x = x; w->viewport_focus_coordinates.y = y; @@ -1042,6 +1174,20 @@ static void window_park_init_viewport(rct_window *w) window_invalidate(w); } +void toggle_land_rights_window(rct_window *parkWindow, int widgetIndex) +{ + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 14) { + tool_cancel(); + } + else { + show_gridlines(); + tool_set(parkWindow, widgetIndex, 2); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + window_land_rights_open(); + } +} + #pragma endregion #pragma region Rating page @@ -1070,7 +1216,7 @@ void window_park_rating_open() window_invalidate(window); window->widgets = window_park_rating_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_RATING]; - window->var_020 = 0; + window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_RATING]; window->event_handlers = (uint32*)window_park_rating_events; window_init_scroll_widgets(window); } @@ -1125,6 +1271,7 @@ static void window_park_rating_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; if (w->widgets != widgets) { @@ -1133,9 +1280,7 @@ static void window_park_rating_invalidate() } window_park_set_pressed_tab(w); - - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + window_park_prepare_window_title_text(); window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_7); window_park_anchor_border_widgets(w); @@ -1204,7 +1349,7 @@ void window_park_guests_open() window_invalidate(window); window->widgets = window_park_guests_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_GUESTS]; - window->var_020 = 0; + window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_GUESTS]; window->event_handlers = (uint32*)window_park_guests_events; window_init_scroll_widgets(window); } @@ -1260,6 +1405,7 @@ static void window_park_guests_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; if (w->widgets != widgets) { @@ -1268,9 +1414,7 @@ static void window_park_guests_invalidate() } window_park_set_pressed_tab(w); - - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + window_park_prepare_window_title_text(); window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_7); window_park_anchor_border_widgets(w); @@ -1367,12 +1511,12 @@ static void window_park_price_mousedown(int widgetIndex, rct_window*w, rct_widge window_park_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_INCREASE_PRICE: - newFee = min(1000, RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, uint16) + 10); - game_do_command(0, 1, 0, 0, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, newFee, 0); + newFee = min(MONEY(100,00), RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) + MONEY(1,00)); + park_set_entrance_fee(newFee); break; case WIDX_DECREASE_PRICE: - newFee = max(0, RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, uint16) - 10); - game_do_command(0, 1, 0, 0, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, newFee, 0); + newFee = max(MONEY(0,00), RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) - MONEY(1,00)); + park_set_entrance_fee(newFee); break; } } @@ -1397,6 +1541,7 @@ static void window_park_price_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; if (w->widgets != widgets) { @@ -1405,11 +1550,11 @@ static void window_park_price_invalidate() } window_park_set_pressed_tab(w); + window_park_prepare_window_title_text(); - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); - - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) { + // If the entry price is locked at free, disable the widget, unless the unlock_all_prices cheat is active. + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) + && (!gConfigCheat.unlock_all_prices)) { window_park_price_widgets[WIDX_PRICE].type = WWT_12; window_park_price_widgets[WIDX_INCREASE_PRICE].type = WWT_EMPTY; window_park_price_widgets[WIDX_DECREASE_PRICE].type = WWT_EMPTY; @@ -1519,6 +1664,7 @@ static void window_park_stats_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; if (w->widgets != widgets) { @@ -1527,9 +1673,7 @@ static void window_park_stats_invalidate() } window_park_set_pressed_tab(w); - - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + window_park_prepare_window_title_text(); window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_7); window_park_anchor_border_widgets(w); @@ -1554,7 +1698,7 @@ static void window_park_stats_paint() y = w->y + window_park_awards_widgets[WIDX_PAGE_BACKGROUND].top + 4; // Draw park size - parkSize = RCT2_GLOBAL(RCT2_ADDRESS_PARK_SIZE, sint16) * 10; + parkSize = RCT2_GLOBAL(RCT2_ADDRESS_PARK_SIZE, uint16) * 10; stringIndex = STR_PARK_SIZE_METRIC_LABEL; if (!RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8)) { stringIndex = STR_PARK_SIZE_IMPERIAL_LABEL; @@ -1565,7 +1709,7 @@ static void window_park_stats_paint() y += 10; // Draw number of rides / attractions - if (w->list_information_type != -1) { + if (w->list_information_type != (uint16)-1) { RCT2_GLOBAL(0x013CE952, uint32) = w->list_information_type; gfx_draw_string_left(dpi, STR_NUMBER_OF_RIDES_LABEL, (void*)0x013CE952, 0, x, y); } @@ -1610,7 +1754,7 @@ void window_park_objective_open() window_invalidate(window); window->widgets = window_park_objective_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_OBJECTIVE]; - window->var_020 = 0; + window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_OBJECTIVE]; window->event_handlers = (uint32*)window_park_objective_events; window_init_scroll_widgets(window); window->x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2 - 115; @@ -1649,7 +1793,8 @@ static void window_park_objective_mouseup() STR_ENTER_NAME, STR_PLEASE_ENTER_YOUR_NAME_FOR_THE_SCENARIO_CHART, 0, - 0 + 0, + 32 ); break; } @@ -1706,12 +1851,10 @@ static void window_park_objective_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); window_park_set_pressed_tab(w); - - // Set window title arguments - *((uint16*)0x013CE952) = RCT2_GLOBAL(0x013573D4, uint16); - *((uint32*)0x013CE954) = RCT2_GLOBAL(0x013573D8, uint32); + window_park_prepare_window_title_text(); // if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT) @@ -1799,7 +1942,7 @@ void window_park_awards_open() window_invalidate(window); window->widgets = window_park_awards_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_AWARDS]; - window->var_020 = 0; + window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_AWARDS]; window->event_handlers = (uint32*)window_park_awards_events; window_init_scroll_widgets(window); } @@ -1854,6 +1997,7 @@ static void window_park_awards_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; if (w->widgets != widgets) { @@ -1862,9 +2006,7 @@ static void window_park_awards_invalidate() } window_park_set_pressed_tab(w); - - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); - RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + window_park_prepare_window_title_text(); window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_7); window_park_anchor_border_widgets(w); @@ -1891,7 +2033,7 @@ static void window_park_awards_paint() count = 0; for (i = 0; i < MAX_AWARDS; i++) { - award = &RCT2_ADDRESS(RCT2_ADDRESS_AWARD_LIST, rct_award)[i]; + award = &gCurrentAwards[i]; if (award->time == 0) continue; @@ -1936,14 +2078,15 @@ static void window_park_set_page(rct_window *w, int page) } w->enabled_widgets = window_park_page_enabled_widgets[page]; - w->var_020 = RCT2_GLOBAL(0x0097BAE0 + (page * 4), uint32); + w->hold_down_widgets = window_park_page_hold_down_widgets[page]; w->event_handlers = window_park_page_events[page]; w->widgets = window_park_page_widgets[page]; window_park_set_disabled_tabs(w); window_invalidate(w); - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); + window_event_invalidate_call(w); + window_event_update_call(w); if (listen != 0 && w->viewport != NULL) w->viewport->flags |= VIEWPORT_FLAG_SOUND_ON; } diff --git a/src/windows/publisher_credits.c b/src/windows/publisher_credits.c index 1a77ac8a52..270a2d790c 100644 --- a/src/windows/publisher_credits.c +++ b/src/windows/publisher_credits.c @@ -88,15 +88,13 @@ void window_publisher_credits_open() if (window != NULL) return; - window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 210, - max(28, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 192), + window = window_create_centred( 420, 384, (uint32*)window_publisher_credits_events, WC_PUBLISHER_CREDITS, 0 - ); + ); window->widgets = window_publisher_credits_widgets; window->enabled_widgets = 1 << WIDX_CLOSE; @@ -132,13 +130,11 @@ static void window_publisher_credits_mouseup() */ static void window_publisher_credits_scrollgetsize() { - int y = 820; + int width, height; -#ifdef _MSC_VER - __asm mov edx, y -#else - __asm__("mov edx, %[y] " : [y] "+m" (y)); -#endif + width = 0; + height = 820; + window_scrollsize_set_registers(width, height); } /** diff --git a/src/windows/research.c b/src/windows/research.c index a06bc5a02c..32c5792a6f 100644 --- a/src/windows/research.c +++ b/src/windows/research.c @@ -30,6 +30,7 @@ #include "../sprites.h" #include "../world/scenery.h" #include "dropdown.h" +#include "../interface/themes.h" enum { WINDOW_RESEARCH_PAGE_DEVELOPMENT, @@ -235,9 +236,6 @@ void window_research_open() w->page = 0; w->frame_no = 0; w->disabled_widgets = 0; - w->colours[0] = 1; - w->colours[1] = 19; - w->colours[2] = 19; research_update_uncompleted_types(); } @@ -249,7 +247,7 @@ void window_research_open() w->widgets = window_research_page_widgets[0]; w->enabled_widgets = window_research_page_enabled_widgets[0]; - w->var_020 = RCT2_GLOBAL(0x00988E3C, uint32); + w->hold_down_widgets = 0; w->event_handlers = window_research_page_events[0]; w->pressed_widgets = 0; w->disabled_widgets = 0; @@ -304,6 +302,7 @@ static void window_research_development_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_research_page_widgets[WINDOW_RESEARCH_PAGE_DEVELOPMENT]) { w->widgets = window_research_page_widgets[WINDOW_RESEARCH_PAGE_DEVELOPMENT]; @@ -339,42 +338,56 @@ static void window_research_development_paint() x = w->x + 10; y = w->y + window_research_development_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].top + 12; - // Research type - stringId = STR_RESEARCH_UNKNOWN; - if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { - stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8); - if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 1) { - uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint32); - if (typeId >= 0x10000) { - rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); - stringId = rideEntry->var_008 & 0x1000 ? - rideEntry->name : - ((typeId >> 8) & 0xFF) + 2; - } else { - stringId = g_scenerySetEntries[typeId]->name; + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) == RESEARCH_STAGE_FINISHED_ALL){ + stringId = STR_RESEARCH_UNKNOWN; + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0); + y += 25; + // Progress + stringId = 2680; + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); + y += 15; + + RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; + gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); + } + else{ + // Research type + stringId = STR_RESEARCH_UNKNOWN; + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { + stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8); + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 1) { + uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint32); + if (typeId >= 0x10000) { + rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); + stringId = rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME ? + rideEntry->name : + ((typeId >> 8) & 0xFF) + 2; + } + else { + stringId = g_scenerySetEntries[typeId]->name; + } } } - } - gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0); - y += 25; + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0); + y += 25; - // Progress - stringId = 2285 + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8); - gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); - y += 15; + // Progress + stringId = 2285 + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8); + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); + y += 15; - // Expected - RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; - if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { - uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8); - if (expectedDay != 255) { - RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay; - RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_MONTH_MARCH + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8); - RCT2_GLOBAL(0x013CE952, uint16) = 2289; + // Expected + RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { + uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8); + if (expectedDay != 255) { + RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay; + RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_MONTH_MARCH + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8); + RCT2_GLOBAL(0x013CE952, uint16) = 2289; + } } + gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); } - gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); - // Last development x = w->x + 10; y = w->y + window_research_development_widgets[WIDX_LAST_DEVELOPMENT_GROUP].top + 12; @@ -384,7 +397,7 @@ static void window_research_development_paint() if (typeId != 0xFFFFFFFF) { if (typeId >= 0x10000) { rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); - stringId = rideEntry->var_008 & 0x1000 ? + stringId = rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME ? rideEntry->name : ((typeId >> 8) & 0xFF) + 2; @@ -430,7 +443,7 @@ static void window_research_funding_mouseup() case WIDX_SCENERY_AND_THEMING: activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); activeResearchTypes ^= 1 << (widgetIndex - WIDX_TRANSPORT_RIDES); - game_do_command(0, (1 << 8) | 1, 0, activeResearchTypes, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0); + research_set_priority(activeResearchTypes); break; } } @@ -458,7 +471,7 @@ static void window_research_funding_mousedown(int widgetIndex, rct_window *w, rc w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, 4, dropdownWidget->right - dropdownWidget->left - 3 ); @@ -482,7 +495,7 @@ static void window_research_funding_dropdown() if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON || dropdownIndex == -1) return; - game_do_command(0, 1, 0, dropdownIndex, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0); + research_set_funding(dropdownIndex); window_invalidate(w); } @@ -507,6 +520,7 @@ static void window_research_funding_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); if (w->widgets != window_research_page_widgets[WINDOW_RESEARCH_PAGE_FUNDING]) { w->widgets = window_research_page_widgets[WINDOW_RESEARCH_PAGE_FUNDING]; @@ -515,8 +529,9 @@ static void window_research_funding_invalidate() window_research_set_pressed_tab(w); - if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { - window_research_funding_widgets[WIDX_FUNDING_GROUP].type = WWT_EMPTY; + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) || + (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) == RESEARCH_STAGE_FINISHED_ALL)) { + //window_research_funding_widgets[WIDX_FUNDING_GROUP].type = WWT_EMPTY; window_research_funding_widgets[WIDX_RESEARCH_FUNDING].type = WWT_EMPTY; window_research_funding_widgets[WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON].type = WWT_EMPTY; } else { @@ -591,7 +606,7 @@ static void window_research_set_page(rct_window *w, int page) } w->enabled_widgets = window_research_page_enabled_widgets[page]; - w->var_020 = RCT2_ADDRESS(0x00988E3C, uint32)[page]; + w->hold_down_widgets = 0; w->event_handlers = window_research_page_events[page]; w->widgets = window_research_page_widgets[page]; w->disabled_widgets = 0; @@ -605,8 +620,8 @@ static void window_research_set_page(rct_window *w, int page) w->width = 320; w->height = 207; } - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); + window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); diff --git a/src/windows/ride.c b/src/windows/ride.c index 3d279f5a6f..c84958848f 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -19,8 +19,11 @@ *****************************************************************************/ #include "../addresses.h" +#include "../audio/audio.h" +#include "../config.h" #include "../game.h" #include "../input.h" +#include "../interface/themes.h" #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" @@ -28,6 +31,7 @@ #include "../peep/staff.h" #include "../ride/ride.h" #include "../ride/ride_data.h" +#include "../ride/track.h" #include "../sprites.h" #include "../windows/error.h" #include "../world/map.h" @@ -36,18 +40,18 @@ #define var_496(w) RCT2_GLOBAL((int)w + 0x496, uint16) -enum WINDOW_PARK_PAGE { - WINDOW_PARK_PAGE_MAIN, - WINDOW_PARK_PAGE_VEHICLE, - WINDOW_PARK_PAGE_OPERATING, - WINDOW_PARK_PAGE_MAINTENANCE, - WINDOW_PARK_PAGE_COLOUR, - WINDOW_PARK_PAGE_MUSIC, - WINDOW_PARK_PAGE_MEASUREMENTS, - WINDOW_PARK_PAGE_GRAPHS, - WINDOW_PARK_PAGE_INCOME, - WINDOW_PARK_PAGE_CUSTOMER, - WINDOW_PARK_PAGE_COUNT +enum { + WINDOW_RIDE_PAGE_MAIN, + WINDOW_RIDE_PAGE_VEHICLE, + WINDOW_RIDE_PAGE_OPERATING, + WINDOW_RIDE_PAGE_MAINTENANCE, + WINDOW_RIDE_PAGE_COLOUR, + WINDOW_RIDE_PAGE_MUSIC, + WINDOW_RIDE_PAGE_MEASUREMENTS, + WINDOW_RIDE_PAGE_GRAPHS, + WINDOW_RIDE_PAGE_INCOME, + WINDOW_RIDE_PAGE_CUSTOMER, + WINDOW_RIDE_PAGE_COUNT }; #pragma region Widgets @@ -77,6 +81,9 @@ enum { WIDX_RENAME, WIDX_LOCATE, WIDX_DEMOLISH, + WIDX_CLOSE_LIGHT, + WIDX_TEST_LIGHT, + WIDX_OPEN_LIGHT, WIDX_VEHICLE_TYPE = 14, WIDX_VEHICLE_TYPE_DROPDOWN, @@ -117,6 +124,7 @@ enum { WIDX_INSPECTION_INTERVAL = 14, WIDX_INSPECTION_INTERVAL_DROPDOWN, WIDX_LOCATE_MECHANIC, + WIDX_FORCE_BREAKDOWN, WIDX_TRACK_PREVIEW = 14, WIDX_TRACK_COLOUR_SCHEME, @@ -171,6 +179,8 @@ enum { WIDX_SHOW_GUESTS_QUEUING }; +#define RCT1_LIGHT_OFFSET 4 + // 0x009ADC34 static rct_widget window_ride_main_widgets[] = { { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, @@ -197,6 +207,9 @@ static rct_widget window_ride_main_widgets[] = { { WWT_FLATBTN, 1, 291, 314, 94, 117, SPR_RENAME, STR_NAME_RIDE_TIP }, { WWT_FLATBTN, 1, 291, 314, 118, 141, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, { WWT_FLATBTN, 1, 291, 314, 142, 165, SPR_DEMOLISH, STR_DEMOLISH_RIDE_TIP }, + { WWT_IMGBTN, 1, 296, 309, 48, 61, SPR_G2_RCT1_CLOSE_BUTTON_0, 5293 }, + { WWT_IMGBTN, 1, 296, 309, 62, 75, SPR_G2_RCT1_TEST_BUTTON_0, 5294 }, + { WWT_IMGBTN, 1, 296, 309, 76, 89, SPR_G2_RCT1_OPEN_BUTTON_0, 5295 }, { WIDGETS_END }, }; @@ -294,6 +307,7 @@ static rct_widget window_ride_maintenance_widgets[] = { { WWT_DROPDOWN, 1, 107, 308, 71, 82, 0, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE }, { WWT_DROPDOWN_BUTTON, 1, 297, 307, 72, 81, 876, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE }, { WWT_FLATBTN, 1, 289, 312, 108, 131, 0xFFFFFFFF, STR_LOCATE_NEAREST_AVAILABLE_MECHANIC_TIP }, + { WWT_FLATBTN, 1, 265, 288, 108, 131, SPR_NO_ENTRY, 5292 }, { WIDGETS_END }, }; @@ -477,10 +491,10 @@ static rct_widget *window_ride_page_widgets[] = { }; const uint64 window_ride_page_enabled_widgets[] = { - 0x00000000007DBFF4, + 0x0000000003FDBFF4, 0x00000000001EFFF4, 0x0000019E777DBFF4, - 0x000000000001FFF4, + 0x000000000003FFF4, 0x00000003F37F3FF4, 0x000000000001FFF4, 0x000000000007FFF4, @@ -489,6 +503,19 @@ const uint64 window_ride_page_enabled_widgets[] = { 0x000000000001FFF4 }; +const uint64 window_ride_page_hold_down_widgets[] = { + 0x0000000000000000, + 0x0000000000000000, + 0x00000000330D8000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000630000, + 0x0000000000000000 +}; + #pragma endregion #pragma region Events @@ -586,6 +613,8 @@ static void window_ride_customer_update(rct_window *w); static void window_ride_customer_invalidate(); static void window_ride_customer_paint(); +static void window_ride_set_colours(); + // 0x0098DFD4 static void* window_ride_main_events[] = { window_ride_emptysub, @@ -780,7 +809,7 @@ static void* window_ride_music_events[] = { // 0x0098DE14 static void* window_ride_measurements_events[] = { - window_ride_emptysub, + window_ride_measurements_close, window_ride_measurements_mouseup, window_ride_measurements_resize, window_ride_measurements_mousedown, @@ -944,7 +973,7 @@ static void window_ride_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, in */ static void window_ride_draw_tab_main(rct_drawpixelinfo *dpi, rct_window *w) { - int widgetIndex = WIDX_TAB_1 + WINDOW_PARK_PAGE_MAIN; + int widgetIndex = WIDX_TAB_1 + WINDOW_RIDE_PAGE_MAIN; if (!(w->disabled_widgets & (1LL << widgetIndex))) { int spriteIndex; @@ -953,17 +982,17 @@ static void window_ride_draw_tab_main(rct_drawpixelinfo *dpi, rct_window *w) switch (gRideClassifications[rideType]) { case RIDE_CLASS_RIDE: spriteIndex = 5442; - if (w->page == WINDOW_PARK_PAGE_MAIN) + if (w->page == WINDOW_RIDE_PAGE_MAIN) spriteIndex += (w->frame_no / 4) % 16; break; case RIDE_CLASS_SHOP_OR_STALL: spriteIndex = 5351; - if (w->page == WINDOW_PARK_PAGE_MAIN) + if (w->page == WINDOW_RIDE_PAGE_MAIN) spriteIndex += (w->frame_no / 4) % 16; break; case RIDE_CLASS_KIOSK_OR_FACILITY: spriteIndex = 5367; - if (w->page == WINDOW_PARK_PAGE_MAIN) + if (w->page == WINDOW_RIDE_PAGE_MAIN) spriteIndex += (w->frame_no / 4) % 8; break; } @@ -981,11 +1010,10 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) rct_ride *ride; rct_widget *widget; int widgetIndex, spriteIndex, x, y, width, height; - uint8 *ebp; rct_ride_type *rideEntry; vehicle_colour vehicleColour; - widgetIndex = WIDX_TAB_1 + WINDOW_PARK_PAGE_VEHICLE; + widgetIndex = WIDX_TAB_1 + WINDOW_RIDE_PAGE_VEHICLE; widget = &w->widgets[widgetIndex]; if (!(w->disabled_widgets & (1LL << widgetIndex))) { @@ -993,7 +1021,7 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) y = widget->top + 1; width = widget->right - x; height = widget->bottom - 3 - y; - if (w->page == WINDOW_PARK_PAGE_VEHICLE) + if (w->page == WINDOW_RIDE_PAGE_VEHICLE) height += 4; x += w->x; @@ -1010,7 +1038,7 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, 0, 0, 0, 0, 0, 0); rideEntry = ride_get_entry(ride); - if (rideEntry->var_008 & 1) { + if (rideEntry->flags & RIDE_ENTRY_FLAG_0) { dpi->zoom_level = 1; dpi->width *= 2; dpi->height *= 2; @@ -1020,22 +1048,23 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) dpi->y *= 2; } - ebp = (uint8*)rideEntry + (RCT2_ADDRESS(0x00F64E38, uint8)[rideEntry->var_013] * 101); - height += RCT2_GLOBAL(ebp + 0x24, sint8); + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[rideEntry->tab_vehicle]]; + height += rideVehicleEntry->var_0A; vehicleColour = ride_get_vehicle_colour(ride, 0); spriteIndex = 32; - if (w->page == WINDOW_PARK_PAGE_VEHICLE) + if (w->page == WINDOW_RIDE_PAGE_VEHICLE) spriteIndex += w->frame_no; - spriteIndex /= (RCT2_GLOBAL(ebp + 0x2C, uint16) & 0x800) ? 4 : 2; - spriteIndex &= RCT2_GLOBAL(ebp + 0x1A, uint16); - spriteIndex *= RCT2_GLOBAL(ebp + 0x30, uint16); - spriteIndex += RCT2_GLOBAL(ebp + 0x32, uint32); + spriteIndex /= (rideVehicleEntry->var_12 & 0x800) ? 4 : 2; + spriteIndex &= rideVehicleEntry->var_00; + spriteIndex *= rideVehicleEntry->var_16; + spriteIndex += rideVehicleEntry->base_image_id; spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); spriteIndex |= 0x80000000; gfx_draw_sprite(dpi, spriteIndex, x, y, vehicleColour.additional_2); + rct2_free(dpi); } } @@ -1046,12 +1075,12 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) static void window_ride_draw_tab_customer(rct_drawpixelinfo *dpi, rct_window *w) { int spriteIndex; - int widgetIndex = WIDX_TAB_1 + WINDOW_PARK_PAGE_CUSTOMER; + int widgetIndex = WIDX_TAB_1 + WINDOW_RIDE_PAGE_CUSTOMER; rct_widget *widget = &w->widgets[widgetIndex]; if (!(w->disabled_widgets & (1LL << widgetIndex))) { spriteIndex = 0; - if (w->page == WINDOW_PARK_PAGE_CUSTOMER) + if (w->page == WINDOW_RIDE_PAGE_CUSTOMER) spriteIndex = w->var_492 & ~3; spriteIndex += RCT2_GLOBAL(RCT2_GLOBAL(0x00982708, uint32), uint32); @@ -1069,15 +1098,61 @@ static void window_ride_draw_tab_customer(rct_drawpixelinfo *dpi, rct_window *w) static void window_ride_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) { window_ride_draw_tab_vehicle(dpi, w); - window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_OPERATING, 5201); - window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_MAINTENANCE, 5205); - window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_INCOME, 5253); + window_ride_draw_tab_image(dpi, w, WINDOW_RIDE_PAGE_OPERATING, 5201); + window_ride_draw_tab_image(dpi, w, WINDOW_RIDE_PAGE_MAINTENANCE, 5205); + window_ride_draw_tab_image(dpi, w, WINDOW_RIDE_PAGE_INCOME, 5253); window_ride_draw_tab_main(dpi, w); - window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_MEASUREMENTS, 5229); - window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_COLOUR, 5221); - window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_GRAPHS, 5237); + window_ride_draw_tab_image(dpi, w, WINDOW_RIDE_PAGE_MEASUREMENTS, 5229); + window_ride_draw_tab_image(dpi, w, WINDOW_RIDE_PAGE_COLOUR, 5221); + window_ride_draw_tab_image(dpi, w, WINDOW_RIDE_PAGE_GRAPHS, 5237); window_ride_draw_tab_customer(dpi, w); - window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_MUSIC, 5335); + window_ride_draw_tab_image(dpi, w, WINDOW_RIDE_PAGE_MUSIC, 5335); +} + +/** +* +* rct2: 0x006AEB9F +*/ +void window_ride_disable_tabs(rct_window *w) +{ + uint32 disabled_tabs = 0; + rct_ride *ride = GET_RIDE(w->number & 0xFF); + + uint8 ride_type = ride->type; // ecx + + if ((RCT2_GLOBAL(0x97CF40 + ride_type * 8, uint32) & 0x200) == 0) + disabled_tabs |= (1 << WIDX_TAB_8); // 0x800 + + if (ride_type == RIDE_TYPE_MINI_GOLF) + disabled_tabs |= (1 << WIDX_TAB_2 | 1 << WIDX_TAB_3 | 1 << WIDX_TAB_4); // 0xE0 + + if ((RCT2_GLOBAL(0x97CF40 + ride_type * 8, uint32) & 0x2000) != 0) + disabled_tabs |= (1 << WIDX_TAB_2); // 0x20 + + if ((RCT2_GLOBAL(0x97CF40 + ride_type * 8, uint32) & 0x4000007) == 0 && + (RCT2_GLOBAL(0x97D4F2 + ride_type * 8, uint16) & 0x20) == 0) + disabled_tabs |= (1 << WIDX_TAB_5); // 0x100 + + if ((RCT2_GLOBAL(0x97CF40 + ride_type * 8, uint32) & 0x20000) != 0) + disabled_tabs |= (1 << WIDX_TAB_3 | 1 << WIDX_TAB_4 | 1 << WIDX_TAB_7); // 0x4C0 + + if ((RCT2_GLOBAL(0x97D4F2 + ride_type * 8, uint32) & 0x4) == 0) + disabled_tabs |= (1 << WIDX_TAB_6); // 0x200 + + if (ride_type == RIDE_TYPE_CASH_MACHINE || + ride_type == RIDE_TYPE_FIRST_AID || + (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) != 0) + disabled_tabs |= (1 << WIDX_TAB_9); // 0x1000 + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint32) & SCREEN_FLAGS_TRACK_DESIGNER) != 0) + disabled_tabs |= (1 << WIDX_TAB_4 | 1 << WIDX_TAB_6 | 1 << WIDX_TAB_9 | 1 << WIDX_TAB_10); // 0x3280 + + rct_ride_type *type = GET_RIDE_ENTRY(ride->subtype); + + if ((type->flags & RIDE_ENTRY_FLAG_19) != 0) + disabled_tabs |= (1 << WIDX_TAB_5); // 0x100 + + w->disabled_widgets = disabled_tabs; } /** @@ -1091,7 +1166,7 @@ rct_window *window_ride_open(int rideIndex) uint8 *rideEntryIndexPtr; int numSubTypes, quadIndex, bitIndex; - w = window_create_auto_pos(316, 180, window_ride_page_events[0], WC_RIDE, 0x400); + w = window_create_auto_pos(316, 180, window_ride_page_events[0], WC_RIDE, WF_10 | WF_RESIZABLE); w->widgets = window_ride_page_widgets[0]; w->enabled_widgets = window_ride_page_enabled_widgets[0]; w->number = rideIndex; @@ -1102,15 +1177,11 @@ rct_window *window_ride_open(int rideIndex) w->list_information_type = 0; w->var_492 = 0; w->var_494 = 0; - RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + window_ride_disable_tabs(w); w->min_width = 316; w->min_height = 180; w->max_width = 500; w->max_height = 450; - w->flags |= WF_RESIZABLE; - w->colours[0] = 1; - w->colours[1] = 26; - w->colours[2] = 11; ride = GET_RIDE(rideIndex); numSubTypes = 0; @@ -1149,16 +1220,16 @@ rct_window *window_ride_main_open(int rideIndex) } } - w->page = 0; + w->page = WINDOW_RIDE_PAGE_MAIN; w->width = 316; w->height = 180; window_invalidate(w); - w->widgets = window_ride_page_widgets[0]; - w->enabled_widgets = 0x007DBFF4; - w->var_020 = 0; - w->event_handlers = window_ride_page_events[0]; + w->widgets = window_ride_page_widgets[WINDOW_RIDE_PAGE_MAIN]; + w->enabled_widgets = window_ride_page_enabled_widgets[WINDOW_RIDE_PAGE_MAIN]; + w->hold_down_widgets = window_ride_page_hold_down_widgets[WINDOW_RIDE_PAGE_MAIN]; + w->event_handlers = window_ride_page_events[WINDOW_RIDE_PAGE_MAIN]; w->pressed_widgets = 0; - RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + window_ride_disable_tabs(w); window_init_scroll_widgets(w); w->ride.view = 0; window_ride_init_viewport(w); @@ -1178,7 +1249,7 @@ rct_window *window_ride_open_station(int rideIndex, int stationIndex) ride = GET_RIDE(rideIndex); - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13)) return window_ride_main_open(rideIndex); w = window_bring_to_front_by_number(WC_RIDE, rideIndex); @@ -1195,17 +1266,17 @@ rct_window *window_ride_open_station(int rideIndex, int stationIndex) tool_cancel(); } - w->page = WINDOW_PARK_PAGE_MAIN; + w->page = WINDOW_RIDE_PAGE_MAIN; w->width = 316; w->height = 180; window_invalidate(w); w->widgets = window_ride_page_widgets[w->page]; w->enabled_widgets = window_ride_page_enabled_widgets[w->page]; - w->var_020 = RCT2_ADDRESS(0x0098DD68, uint32)[w->page]; + w->hold_down_widgets = window_ride_page_hold_down_widgets[w->page]; w->event_handlers = window_ride_page_events[w->page]; w->pressed_widgets = 0; - RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + window_ride_disable_tabs(w); window_init_scroll_widgets(w); // View @@ -1224,7 +1295,7 @@ rct_window *window_ride_open_track(rct_map_element *mapElement) { int rideIndex = mapElement->properties.track.ride_index; if ( - ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_ENTRANCE) || + (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) || (RCT2_ADDRESS(0x0099BA64, uint8)[mapElement->properties.track.type * 16] & 0x10) ) { // Open ride window in station view @@ -1304,17 +1375,17 @@ rct_window *window_ride_open_vehicle(rct_vehicle *vehicle) w->ride.var_482 = -1; } - w->page = WINDOW_PARK_PAGE_MAIN; + w->page = WINDOW_RIDE_PAGE_MAIN; w->width = 316; w->height = 180; window_invalidate(w); w->widgets = window_ride_page_widgets[w->page]; w->enabled_widgets = window_ride_page_enabled_widgets[w->page]; - w->var_020 = RCT2_ADDRESS(0x0098DD68, uint32)[w->page]; + w->hold_down_widgets = window_ride_page_hold_down_widgets[w->page]; w->event_handlers = window_ride_page_events[w->page]; w->pressed_widgets = 0; - RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + window_ride_disable_tabs(w); window_init_scroll_widgets(w); w->ride.view = view; @@ -1338,28 +1409,33 @@ static void window_ride_set_page(rct_window *w, int page) // Set listen only to viewport listen = 0; - if (page == WINDOW_PARK_PAGE_MAIN && w->page == WINDOW_PARK_PAGE_MAIN && w->viewport != NULL && !(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) + if (page == WINDOW_RIDE_PAGE_MAIN && w->page == WINDOW_RIDE_PAGE_MAIN && w->viewport != NULL && !(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) listen++; w->page = page; w->frame_no = 0; w->var_492 = 0; + + if (page == WINDOW_RIDE_PAGE_VEHICLE){ + // Reload the vehicle settings + RCT2_CALLPROC_X(0x006DD57D, 0, 0, 0, w->number, 0, 0, 0); + } + if (w->viewport != NULL) { w->viewport->width = 0; w->viewport = NULL; } w->enabled_widgets = window_ride_page_enabled_widgets[page]; - w->var_020 = RCT2_ADDRESS(0x0098DD68, uint32)[page]; + w->hold_down_widgets = window_ride_page_hold_down_widgets[page]; w->event_handlers = window_ride_page_events[page]; w->pressed_widgets = 0; w->widgets = window_ride_page_widgets[page]; - RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + window_ride_disable_tabs(w); window_invalidate(w); - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); - + window_event_resize_call(w); + window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); @@ -1370,7 +1446,7 @@ static void window_ride_set_page(rct_window *w, int page) static void window_ride_set_pressed_tab(rct_window *w) { int i; - for (i = 0; i < WINDOW_PARK_PAGE_COUNT; i++) + for (i = 0; i < WINDOW_RIDE_PAGE_COUNT; i++) w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); } @@ -1394,7 +1470,7 @@ static void window_ride_anchor_border_widgets(rct_window *w) */ static void window_ride_init_viewport(rct_window *w) { - if (w->page != WINDOW_PARK_PAGE_MAIN) return; + if (w->page != WINDOW_RIDE_PAGE_MAIN) return; rct_ride* ride = GET_RIDE(w->number); int eax = w->viewport_focus_coordinates.var_480 - 1; @@ -1413,7 +1489,7 @@ static void window_ride_init_viewport(rct_window *w) focus.sprite.sprite_id = ride->vehicles[eax]; rct_ride_type* ride_entry = ride_get_entry(ride); - if (ride_entry->var_013 != 0){ + if (ride_entry->tab_vehicle != 0){ rct_vehicle* vehicle = GET_VEHICLE(focus.sprite.sprite_id); focus.sprite.sprite_id = vehicle->next_vehicle_on_train; } @@ -1446,9 +1522,8 @@ static void window_ride_init_viewport(rct_window *w) focus.coordinate.z = map_element_height(focus.coordinate.x, focus.coordinate.y) & 0xFFFF; focus.sprite.type |= 0x40; focus.coordinate.zoom = 1; - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x8000){ + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15)) focus.coordinate.zoom = 0; - } } focus.coordinate.var_480 = w->viewport_focus_coordinates.var_480; @@ -1472,7 +1547,7 @@ static void window_ride_init_viewport(rct_window *w) viewport_flags |= VIEWPORT_FLAG_GRIDLINES; } - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); w->viewport_focus_coordinates.x = focus.coordinate.x; w->viewport_focus_coordinates.y = focus.coordinate.y; @@ -1516,26 +1591,8 @@ static void window_ride_init_viewport(rct_window *w) */ void window_ride_construct(rct_window *w) { - int rideIndex = w->number; - window_close_by_class(WC_RIDE_CONSTRUCTION); - w = window_find_by_number(WC_RIDE, rideIndex); - if (w == NULL) - return; - - rct_map_element *trackMapElement; - int trackX, trackY; - - trackMapElement = sub_6CAF80(rideIndex, &trackX, &trackY); - if (trackMapElement == (rct_map_element*)-1) { - sub_6CC3FB(rideIndex); - } else { - trackMapElement = ride_find_track_gap(trackMapElement, &trackX, &trackY); - - w = window_get_main(); - if (w != NULL && ride_modify(trackMapElement, trackX, trackY)) - window_scroll_to_location(w, trackX, trackY, trackMapElement->base_height * 8); - } + ride_construct(w->number); } /** @@ -1548,40 +1605,7 @@ static void window_ride_rename(rct_window *w) ride = GET_RIDE(w->number); RCT2_GLOBAL(0x013CE962, uint32) = ride->name_arguments; - window_text_input_open(w, WIDX_RENAME, STR_RIDE_ATTRACTION_NAME, STR_ENTER_NEW_NAME_FOR_THIS_RIDE_ATTRACTION, ride->name, ride->name_arguments); -} - -/** - * - * rct2: 0x006AF3B3 - */ -static void window_ride_locate(rct_window *w) -{ - rct_window *mainWindow; - int xy, x, y, z; - - if (w->viewport->width == 0) - return; - - xy = w->ride.var_482; - z = w->ride.var_486; - if (xy == -1) - return; - - if (xy & 0x80000000) { - rct_sprite *sprite = &g_sprite_list[xy & 0xFFFF]; - x = sprite->unknown.x; - y = sprite->unknown.y; - z = sprite->unknown.z; - } else { - x = (xy & ~0xC0000000) & 0xFFFF; - y = (xy & ~0xC0000000) >> 16; - z = z >> 16; - } - - mainWindow = window_get_main(); - if (mainWindow != NULL) - window_scroll_to_location(mainWindow, x, y, z); + window_text_input_open(w, WIDX_RENAME, STR_RIDE_ATTRACTION_NAME, STR_ENTER_NEW_NAME_FOR_THIS_RIDE_ATTRACTION, ride->name, ride->name_arguments, 32); } /** @@ -1592,6 +1616,8 @@ static void window_ride_main_mouseup() { short widgetIndex; rct_window *w; + rct_ride *ride; + int status; window_widget_get_registers(w, widgetIndex); @@ -1618,11 +1644,36 @@ static void window_ride_main_mouseup() window_ride_rename(w); break; case WIDX_LOCATE: - window_ride_locate(w); + window_scroll_to_viewport(w); break; case WIDX_DEMOLISH: window_ride_demolish_prompt_open(w->number); break; + case WIDX_CLOSE_LIGHT: + case WIDX_TEST_LIGHT: + case WIDX_OPEN_LIGHT: + + ride = GET_RIDE(w->number); + + switch (widgetIndex - WIDX_CLOSE_LIGHT) { + case 0: + status = RIDE_STATUS_CLOSED; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1004; + break; + case 1: + status = RIDE_STATUS_TESTING; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1003; + break; + case 2: + status = RIDE_STATUS_OPEN; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1002; + break; + } + + RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 8, uint32) = ride->name_arguments; + ride_set_status(w->number, status); + break; } } @@ -1639,7 +1690,10 @@ static void window_ride_main_resize() window_get_register(w); w->flags |= WF_RESIZABLE; - window_set_resize(w, 316, 180, 500, 450); + int minHeight = 180; + if (theme_get_preset()->features.rct1_ride_lights) + minHeight = 200 + RCT1_LIGHT_OFFSET - (ride_type_has_flag(GET_RIDE(w->number)->type, RIDE_TYPE_FLAG_NO_TEST_MODE) ? 14 : 0); + window_set_resize(w, 316, minHeight, 500, 450); viewport = w->viewport; if (viewport != NULL) { @@ -1670,7 +1724,7 @@ static void window_ride_show_view_dropdown(rct_window *w, rct_widget *widget) ride = GET_RIDE(w->number); numItems = 1; - if (!(RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x2000)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13)) { numItems += ride->num_stations; numItems += ride->num_vehicles; } @@ -1735,7 +1789,7 @@ static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) gDropdownItemsArgs[numItems] = STR_CLOSE_RIDE; numItems++; - if (!(RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_TEST_MODE)) { gDropdownItemsFormat[numItems] = 1142; gDropdownItemsArgs[numItems] = STR_TEST_RIDE; numItems++; @@ -1762,7 +1816,7 @@ static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) break; highlightedIndex = 2; - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800) + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_TEST_MODE)) break; if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) break; @@ -1784,7 +1838,7 @@ static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) if (checkedIndex != RIDE_STATUS_CLOSED) checkedIndex = 3 - checkedIndex; - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_TEST_MODE)) { if (checkedIndex != 0) checkedIndex--; if (highlightedIndex != 0) @@ -1846,7 +1900,7 @@ static void window_ride_main_dropdown() dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); ride = GET_RIDE(w->number); - if ((RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800) && dropdownIndex != 0) + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_TEST_MODE) && dropdownIndex != 0) dropdownIndex++; switch (dropdownIndex) { @@ -1864,9 +1918,9 @@ static void window_ride_main_dropdown() break; } - RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->overall_view; + RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 8, uint32) = ride->name_arguments; - game_do_command(0, 1, 0, w->number | (status << 8), GAME_COMMAND_SET_RIDE_OPEN, 0, 0); + ride_set_status(w->number, status); break; } } @@ -1884,12 +1938,12 @@ static void window_ride_main_update(rct_window *w) // Update tab animation w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_1); // Update status ride = GET_RIDE(w->number); - if (!(ride->var_14D & 4)) { + if (!(ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MAIN)) { if (w->ride.view == 0) return; @@ -1911,7 +1965,7 @@ static void window_ride_main_update(rct_window *w) } } - ride->var_14D &= ~4; + ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_MAIN; widget_invalidate(w, WIDX_STATUS); } @@ -1931,10 +1985,7 @@ static void window_ride_main_textinput() if (widgetIndex != WIDX_RENAME || !result) return; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_RENAME_RIDE_ATTRACTION; - game_do_command(1, (w->number << 8) | 1, 0, *((int*)(text + 0)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(text + 8)), *((int*)(text + 4))); - game_do_command(2, (w->number << 8) | 1, 0, *((int*)(text + 12)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(text + 20)), *((int*)(text + 16))); - game_do_command(0, (w->number << 8) | 1, 0, *((int*)(text + 24)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(text + 32)), *((int*)(text + 28))); + ride_set_name(w->number, text); } /** @@ -1958,9 +2009,10 @@ static void window_ride_main_invalidate() { rct_window *w; rct_widget *widgets; - int i; + int i, height; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -1974,13 +2026,17 @@ static void window_ride_main_invalidate() w->disabled_widgets &= ~((1 << 22) | (1 << 19)); if (ride->lifecycle_flags & (RIDE_LIFECYCLE_INDESTRUCTIBLE | RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK)) w->disabled_widgets |= (1 << 22); - if (ride->lifecycle_flags & RIDE_LIFECYCLE_19) + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) w->disabled_widgets |= (1 << 19); RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; window_ride_main_widgets[WIDX_OPEN].image = SPR_CLOSED + ride->status; + window_ride_main_widgets[WIDX_CLOSE_LIGHT].image = SPR_G2_RCT1_CLOSE_BUTTON_0 + (ride->status == RIDE_STATUS_CLOSED) * 2 + widget_is_pressed(w, WIDX_CLOSE_LIGHT); + window_ride_main_widgets[WIDX_TEST_LIGHT].image = SPR_G2_RCT1_TEST_BUTTON_0 + (ride->status == RIDE_STATUS_TESTING) * 2 + widget_is_pressed(w, WIDX_TEST_LIGHT); + window_ride_main_widgets[WIDX_OPEN_LIGHT].image = SPR_G2_RCT1_OPEN_BUTTON_0 + (ride->status == RIDE_STATUS_OPEN) * 2 + widget_is_pressed(w, WIDX_OPEN_LIGHT); + window_ride_anchor_border_widgets(w); // Anchor main page specific widgets @@ -1989,15 +2045,49 @@ static void window_ride_main_invalidate() window_ride_main_widgets[WIDX_STATUS].right = w->width - 26; window_ride_main_widgets[WIDX_STATUS].top = w->height - 13; window_ride_main_widgets[WIDX_STATUS].bottom = w->height - 3; - for (i = WIDX_OPEN; i <= WIDX_DEMOLISH; i++) { - window_ride_main_widgets[i].left = w->width - 25; - window_ride_main_widgets[i].right = w->width - 2; - } window_ride_main_widgets[WIDX_VIEW].right = w->width - 60; window_ride_main_widgets[WIDX_VIEW_DROPDOWN].right = w->width - 61; window_ride_main_widgets[WIDX_VIEW_DROPDOWN].left = w->width - 71; window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); + + if (theme_get_preset()->features.rct1_ride_lights) { + window_ride_main_widgets[WIDX_OPEN].type = WWT_EMPTY; + window_ride_main_widgets[WIDX_CLOSE_LIGHT].type = WWT_IMGBTN; + window_ride_main_widgets[WIDX_TEST_LIGHT].type = (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_TEST_MODE) ? WWT_EMPTY : WWT_IMGBTN); + window_ride_main_widgets[WIDX_OPEN_LIGHT].type = WWT_IMGBTN; + + height = 62; + if (window_ride_main_widgets[WIDX_TEST_LIGHT].type != WWT_EMPTY) { + window_ride_main_widgets[WIDX_TEST_LIGHT].top = height; + window_ride_main_widgets[WIDX_TEST_LIGHT].bottom = height + 13; + height += 14; + } + window_ride_main_widgets[WIDX_OPEN_LIGHT].top = height; + window_ride_main_widgets[WIDX_OPEN_LIGHT].bottom = height + 13; + height += 14 - 24 + RCT1_LIGHT_OFFSET; + + w->min_height = 200 + RCT1_LIGHT_OFFSET - (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_TEST_MODE) ? 14 : 0); + if (w->height < w->min_height) + window_event_resize_call(w); + } + else { + window_ride_main_widgets[WIDX_OPEN].type = WWT_FLATBTN; + window_ride_main_widgets[WIDX_CLOSE_LIGHT].type = WWT_EMPTY; + window_ride_main_widgets[WIDX_TEST_LIGHT].type = WWT_EMPTY; + window_ride_main_widgets[WIDX_OPEN_LIGHT].type = WWT_EMPTY; + height = 46; + } + for (i = WIDX_CLOSE_LIGHT; i <= WIDX_OPEN_LIGHT; i++) { + window_ride_main_widgets[i].left = w->width - 20; + window_ride_main_widgets[i].right = w->width - 7; + } + for (i = WIDX_OPEN; i <= WIDX_DEMOLISH; i++, height += 24) { + window_ride_main_widgets[i].left = w->width - 25; + window_ride_main_widgets[i].right = w->width - 2; + window_ride_main_widgets[i].top = height; + window_ride_main_widgets[i].bottom = height + 23; + } } /** @@ -2061,7 +2151,7 @@ static rct_string_id window_ride_get_status_vehicle(rct_window *w, void *argumen stringId += 23; RCT2_GLOBAL((int)arguments + 4, uint16) = RideNameConvention[ride->type].station_name; - RCT2_GLOBAL((int)arguments + 6, uint16) = vehicle->var_4B + 1; + RCT2_GLOBAL((int)arguments + 6, uint16) = vehicle->current_station + 1; if (ride->num_stations > 1) RCT2_GLOBAL((int)arguments + 4, uint16) += 6; @@ -2190,7 +2280,7 @@ static void window_ride_main_paint() (void*)0x013CE952, 0, w->x + (widget->left + widget->right) / 2, - w->y + widget->top - 1, + w->y + widget->top, widget->right - widget->left ); } @@ -2271,7 +2361,8 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi for (currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != 0xFF; currentRideEntryIndex++) { rideEntryIndex = *currentRideEntryIndex; currentRideEntry = GET_RIDE_ENTRY(rideEntryIndex); - if (currentRideEntry->var_008 & 0x3000) + // Skip if vehicle has the same track type, but not same subtype, unless subtype switching is enabled + if ((currentRideEntry->flags & (RIDE_ENTRY_FLAG_SEPERATE_RIDE | RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME)) && !gConfigInterface.allow_subtype_switching) continue; quadIndex = rideEntryIndex >> 5; @@ -2293,7 +2384,7 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, numItems, widget->right - dropdownWidget->left ); @@ -2306,7 +2397,7 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, ride->var_0CC, widget->right - dropdownWidget->left ); @@ -2328,7 +2419,7 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, maxCars - minCars + 1, widget->right - dropdownWidget->left ); @@ -2338,9 +2429,9 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi gDropdownItemsFormat[i] = 1142; gDropdownItemsArgs[i] = 1024; - if (cars - rideEntry->var_012 > 1) + if (cars - rideEntry->zero_cars > 1) gDropdownItemsArgs[i]++; - gDropdownItemsArgs[i] |= (cars - rideEntry->var_012) << 16; + gDropdownItemsArgs[i] |= (cars - rideEntry->zero_cars) << 16; } gDropdownItemsChecked = (1 << (ride->num_cars_per_train - minCars)); @@ -2380,7 +2471,7 @@ static void window_ride_vehicle_dropdown() break; case WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN: RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1019; - game_do_command(0, (1 << 8) | 1, 0, ((rideEntry->var_00F + dropdownIndex) << 8) | w->number, GAME_COMMAND_9, 0, 0); + game_do_command(0, (1 << 8) | 1, 0, ((rideEntry->min_cars_in_train + dropdownIndex) << 8) | w->number, GAME_COMMAND_9, 0, 0); break; } } @@ -2392,7 +2483,7 @@ static void window_ride_vehicle_dropdown() static void window_ride_vehicle_update(rct_window *w) { w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_2); } @@ -2410,6 +2501,7 @@ static void window_ride_vehicle_invalidate() int carsPerTrain; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -2426,11 +2518,12 @@ static void window_ride_vehicle_invalidate() RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; // Widget setup - carsPerTrain = ride->num_cars_per_train - rideEntry->var_012; + carsPerTrain = ride->num_cars_per_train - rideEntry->zero_cars; // Vehicle type window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE].image = rideEntry->name; - if (var_496(w) <= 1 && (w->enabled_widgets & (1 << WIDX_TAB_10))) { + // Always show a dropdown button when changing subtypes is allowed + if ((var_496(w) <= 1 || (rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE)) && !gConfigInterface.allow_subtype_switching) { window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE].type = WWT_14; window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE_DROPDOWN].type = WWT_EMPTY; w->enabled_widgets &= ~(1 << WIDX_VEHICLE_TYPE); @@ -2441,7 +2534,7 @@ static void window_ride_vehicle_invalidate() } // Trains - if (rideEntry->var_011 > 1) { + if (rideEntry->cars_per_flat_ride > 1) { window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS].type = WWT_DROPDOWN; window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS_DROPDOWN].type = WWT_DROPDOWN_BUTTON; } else { @@ -2450,7 +2543,7 @@ static void window_ride_vehicle_invalidate() } // Cars per train - if (rideEntry->var_012 + 1 < rideEntry->var_010) { + if (rideEntry->zero_cars + 1 < rideEntry->max_cars_in_train) { window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN].image = carsPerTrain > 1 ? 1023 : 1022; window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN].type = WWT_DROPDOWN; window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN].type = WWT_DROPDOWN_BUTTON; @@ -2504,21 +2597,27 @@ static void window_ride_vehicle_paint() gfx_draw_string_left(dpi, 3142, &stringId, 0, x, y); y += 15; - if (!(rideEntry->var_008 & 0x2000) && var_496(w) > 1) { + if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE) && var_496(w) > 1) { // Excitement Factor factor = rideEntry->excitement_multipler; - gfx_draw_string_left(dpi, 3125, &factor, 0, x, y); - y += 10; + if (factor > 0) { + gfx_draw_string_left(dpi, 3125, &factor, 0, x, y); + y += 10; + } // Intensity Factor factor = rideEntry->intensity_multipler; - gfx_draw_string_left(dpi, 3126, &factor, 0, x, y); - y += 10; + if (factor > 0) { + gfx_draw_string_left(dpi, 3126, &factor, 0, x, y); + y += 10; + } // Nausea Factor factor = rideEntry->nausea_multipler; - gfx_draw_string_left(dpi, 3127, &factor, 0, x, y); - y += 10; + if (factor > 0) { + gfx_draw_string_left(dpi, 3127, &factor, 0, x, y); + y += 10; + } } } @@ -2542,7 +2641,7 @@ static void window_ride_vehicle_scrollpaint() rct_ride *ride; rct_ride_type *rideEntry; rct_widget *widget; - int x, y, startX, startY, i, j, vehicleColourIndex, spriteIndex, ebp; + int x, y, startX, startY, i, j, vehicleColourIndex, spriteIndex; rct_vehichle_paintinfo *nextSpriteToDraw, *current, tmp; vehicle_colour vehicleColour; @@ -2560,8 +2659,8 @@ static void window_ride_vehicle_scrollpaint() startX = max(2, ((widget->right - widget->left) - ((ride->num_vehicles - 1) * 36)) / 2 - 25); startY = widget->bottom - widget->top - 4; - ebp = (int)rideEntry + (RCT2_ADDRESS(0x00F64E38, uint8)[0] * 101); - startY += RCT2_GLOBAL(ebp + 0x24, sint8); + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[0]]; + startY += rideVehicleEntry->var_0A; // For each train for (i = 0; i < ride->num_vehicles; i++) { @@ -2571,9 +2670,9 @@ static void window_ride_vehicle_scrollpaint() // For each car in train for (j = 0; j < ride->num_cars_per_train; j++) { - int ebp = (int)rideEntry + (RCT2_ADDRESS(0x00F64E38, uint8)[j] * 101); - x += RCT2_GLOBAL(ebp + 0x1E, uint32) / 17432; - y -= (RCT2_GLOBAL(ebp + 0x1E, uint32) / 2) / 17432; + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[j]]; + x += rideVehicleEntry->var_04 / 17432; + y -= (rideVehicleEntry->var_04 / 2) / 17432; // Get colour of vehicle switch (ride->colour_scheme_type & 3) { @@ -2590,12 +2689,12 @@ static void window_ride_vehicle_scrollpaint() vehicleColour = ride_get_vehicle_colour(ride, vehicleColourIndex); spriteIndex = 16; - if (RCT2_GLOBAL(ebp + 0x2C, uint16) & 0x800) + if (rideVehicleEntry->var_12 & 0x800) spriteIndex /= 2; - spriteIndex &= RCT2_GLOBAL(ebp + 0x1A, uint16); - spriteIndex *= RCT2_GLOBAL(ebp + 0x30, uint16); - spriteIndex += RCT2_GLOBAL(ebp + 0x32, uint32); + spriteIndex &= rideVehicleEntry->var_00; + spriteIndex *= rideVehicleEntry->var_16; + spriteIndex += rideVehicleEntry->base_image_id; spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); spriteIndex |= 0x80000000; @@ -2605,8 +2704,8 @@ static void window_ride_vehicle_scrollpaint() nextSpriteToDraw->tertiary_colour = vehicleColour.additional_2; nextSpriteToDraw++; - x += RCT2_GLOBAL(ebp + 0x1E, uint32) / 17432; - y -= (RCT2_GLOBAL(ebp + 0x1E, uint32) / 2) / 17432; + x += rideVehicleEntry->var_04 / 17432; + y -= (rideVehicleEntry->var_04 / 2) / 17432; } if (ride->type == RIDE_TYPE_REVERSER_ROLLER_COASTER) { @@ -2630,7 +2729,7 @@ static void window_ride_vehicle_scrollpaint() static void set_operating_setting(int rideNumber, uint8 setting, uint8 value) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; - game_do_command(0, (value << 8) | 1, 0, (setting << 8) | rideNumber, GAME_COMMAND_11, 0, 0); + game_do_command(0, (value << 8) | 1, 0, (setting << 8) | rideNumber, GAME_COMMAND_SET_RIDE_SETTING, 0, 0); } static void window_ride_mode_tweak_set(rct_window *w, uint8 value) @@ -2642,7 +2741,7 @@ static void window_ride_mode_tweak_set(rct_window *w, uint8 value) RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1361; if (ride->mode == RIDE_MODE_RACE) RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1738; - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13)) RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1746; if (ride->mode == RIDE_MODE_BUMPERCAR) RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1751; @@ -2657,7 +2756,7 @@ static void window_ride_mode_tweak_set(rct_window *w, uint8 value) ) RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1868; - game_do_command(0, (value << 8) | 1, 0, (4 << 8) | w->number, GAME_COMMAND_11, 0, 0); + game_do_command(0, (value << 8) | 1, 0, (4 << 8) | w->number, GAME_COMMAND_SET_RIDE_SETTING, 0, 0); } /** @@ -2667,8 +2766,15 @@ static void window_ride_mode_tweak_set(rct_window *w, uint8 value) static void window_ride_mode_tweak_increase(rct_window *w) { rct_ride *ride = GET_RIDE(w->number); - uint8 value = ride->var_0D0; - if (value < RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8) + 5, uint8)) + uint8 value = ride->operation_option; + //fast_lift_hill is the cheat that allows maxing out many limits on the Operating tab. + uint8 max_value = gConfigCheat.fast_lift_hill ? 255 : RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8) + 5, uint8); + + //Allow 64 people in mazes under non-cheat settings. The old maximum of 16 was too little for even moderately big mazes. + if(ride->mode == RIDE_MODE_MAZE && !gConfigCheat.fast_lift_hill) + max_value = 64; + + if (value < max_value) value += ride->mode == RIDE_MODE_BUMPERCAR ? 10 : 1; window_ride_mode_tweak_set(w, value); @@ -2681,7 +2787,7 @@ static void window_ride_mode_tweak_increase(rct_window *w) static void window_ride_mode_tweak_decrease(rct_window *w) { rct_ride *ride = GET_RIDE(w->number); - uint8 value = ride->var_0D0; + uint8 value = ride->operation_option; if (value > RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8) + 4, uint8)) value -= ride->mode == RIDE_MODE_BUMPERCAR ? 10 : 1; @@ -2718,11 +2824,11 @@ static void window_ride_mode_dropdown(rct_window *w, rct_widget *widget) } while (*(mode++) != 255); // ? - if (rideEntry->var_008 & 0x8000) + if (rideEntry->flags & RIDE_ENTRY_FLAG_15) numAvailableModes--; // ? - if (rideEntry->var_008 & 0x20000) { + if (rideEntry->flags & RIDE_ENTRY_FLAG_17) { availableModes += 2; numAvailableModes -= 2; } @@ -2737,7 +2843,7 @@ static void window_ride_mode_dropdown(rct_window *w, rct_widget *widget) w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0, + DROPDOWN_FLAG_STAY_OPEN, numAvailableModes, widget->right - dropdownWidget->left ); @@ -2769,7 +2875,7 @@ static void window_ride_load_dropdown(rct_window *w, rct_widget *widget) w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0, + DROPDOWN_FLAG_STAY_OPEN, 5, widget->right - dropdownWidget->left ); @@ -2845,6 +2951,7 @@ static void window_ride_operating_resize() static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) { rct_ride *ride = GET_RIDE(w->number); + uint8 max_lift_hill_speed; switch (widgetIndex) { case WIDX_MODE_TWEAK_INCREASE: @@ -2854,7 +2961,13 @@ static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_ window_ride_mode_tweak_decrease(w); break; case WIDX_LIFT_HILL_SPEED_INCREASE: - set_operating_setting(w->number, 8, min(ride->lift_hill_speed + 1, RCT2_GLOBAL(0x0097D7CA + (ride->type * 4), uint8))); + + if(gConfigCheat.fast_lift_hill) + max_lift_hill_speed = 255; + else + max_lift_hill_speed = RCT2_GLOBAL(0x0097D7CA + (ride->type * 4), uint8); + + set_operating_setting(w->number, 8, min(ride->lift_hill_speed + 1, max_lift_hill_speed)); break; case WIDX_LIFT_HILL_SPEED_DECREASE: set_operating_setting(w->number, 8, max(RCT2_GLOBAL(0x0097D7C9 + (ride->type * 4), uint8), ride->lift_hill_speed - 1)); @@ -2878,7 +2991,7 @@ static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_ window_ride_load_dropdown(w, widget); break; case WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE: - set_operating_setting(w->number, 9, min(ride->num_circuits + 1, 7)); + set_operating_setting(w->number, 9, min(ride->num_circuits + 1, 20)); break; case WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE: set_operating_setting(w->number, 9, max(1, ride->num_circuits - 1)); @@ -2929,12 +3042,12 @@ static void window_ride_operating_update(rct_window *w) rct_ride *ride; w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_3); ride = GET_RIDE(w->number); - if (ride->var_14D & 10) { - ride->var_14D &= ~10; + if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_OPERATING) { + ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_OPERATING; window_invalidate(w); } } @@ -2952,6 +3065,7 @@ static void window_ride_operating_invalidate() rct_string_id format, caption, tooltip; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -2971,7 +3085,7 @@ static void window_ride_operating_invalidate() w->pressed_widgets &= ~0x44700000; // Lift hill speed - if ((rideEntry->var_1B6 & RCT2_ADDRESS(0x01357444, uint32)[ride->type]) & 8) { + if ((rideEntry->enabledTrackPieces & RCT2_ADDRESS(0x01357444, uint32)[ride->type]) & 8) { window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_LABEL].type = WWT_24; window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED].type = WWT_SPINNER; window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_INCREASE].type = WWT_DROPDOWN_BUTTON; @@ -3000,7 +3114,7 @@ static void window_ride_operating_invalidate() // Leave if another vehicle arrives at station if ( - (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x10) && + ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_LEAVE_WHEN_ANOTHER_VEHICLE_ARRIVES_AT_STATION) && ride->num_vehicles > 1 && ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED && ride->mode != RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED @@ -3015,7 +3129,7 @@ static void window_ride_operating_invalidate() } // Synchronise with adjacent stations - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x20) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_CAN_SYNCHRONISE_ADJACENT_STATIONS)) { window_ride_operating_widgets[WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX].type = WWT_CHECKBOX; window_ride_operating_widgets[WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX].image = STR_SYNCHRONISE_WITH_ADJACENT_STATIONS; window_ride_operating_widgets[WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX].tooltip = STR_SYNCHRONISE_WITH_ADJACENT_STATIONS_TIP; @@ -3028,7 +3142,7 @@ static void window_ride_operating_invalidate() // Waiting window_ride_operating_widgets[WIDX_LOAD].image = STR_QUARTER_LOAD + (ride->depart_flags & RIDE_DEPART_WAIT_FOR_LOAD_MASK); - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x4000) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_LOAD_OPTIONS)) { window_ride_operating_widgets[WIDX_LOAD_CHECKBOX].type = WWT_CHECKBOX; window_ride_operating_widgets[WIDX_LOAD].type = WWT_DROPDOWN; window_ride_operating_widgets[WIDX_LOAD_DROPDOWN].type = WWT_DROPDOWN_BUTTON; @@ -3076,24 +3190,25 @@ static void window_ride_operating_invalidate() w->pressed_widgets |= (1 << WIDX_MAXIMUM_LENGTH_CHECKBOX); // Mode specific functionality - RCT2_GLOBAL(0x013CE964, uint16) = ride->var_0D0; + RCT2_GLOBAL(0x013CE964, uint16) = ride->operation_option; switch (ride->mode) { + case RIDE_MODE_POWERED_LAUNCH_PASSTROUGH: case RIDE_MODE_POWERED_LAUNCH: - case RIDE_MODE_POWERED_LAUNCH_35: case RIDE_MODE_UPWARD_LAUNCH: case RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED: - RCT2_GLOBAL(0x013CE964, uint16) = (ride->var_0D0 * 9) / 4; + RCT2_GLOBAL(0x013CE964, uint16) = (ride->launch_speed * 9) / 4; format = 1331; caption = STR_LAUNCH_SPEED; tooltip = STR_LAUNCH_SPEED_TIP; break; case RIDE_MODE_STATION_TO_STATION: - RCT2_GLOBAL(0x013CE964, uint16) = (ride->var_0D0 * 9) / 4; + RCT2_GLOBAL(0x013CE964, uint16) = (ride->speed * 9) / 4; + format = 1331; caption = STR_SPEED; tooltip = STR_SPEED_TIP; break; case RIDE_MODE_RACE: - RCT2_GLOBAL(0x013CE964, uint16) = ride->var_0D0; + RCT2_GLOBAL(0x013CE964, uint16) = ride->num_laps; format = 1736; caption = STR_NUMBER_OF_LAPS; tooltip = STR_NUMBER_OF_LAPS_TIP; @@ -3119,7 +3234,7 @@ static void window_ride_operating_invalidate() format = 1736; caption = STR_MAX_PEOPLE_ON_RIDE; tooltip = STR_MAX_PEOPLE_ON_RIDE_TIP; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13)) format = 0; break; } @@ -3220,13 +3335,13 @@ static void window_ride_maintenance_draw_bar(rct_window *w, rct_drawpixelinfo *d gfx_fill_rect_inset(dpi, x, y, x + 149, y + 8, w->colours[1], 0x30); if (unk & (1 << 31)) { unk &= ~(1 << 31); - if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0 && (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 8)) + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0 && (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 8)) return; } value = ((186 * ((value * 2) & 0xFF)) >> 8) & 0xFF; if (value > 2) { - gfx_fill_rect_inset(dpi, x + 2, y + 1, x + value + 1, y + 8, unk, 0); + gfx_fill_rect_inset(dpi, x + 2, y + 1, x + value + 1, y + 7, unk, 0); } } @@ -3282,30 +3397,96 @@ static void window_ride_maintenance_resize() */ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) { + rct_ride *ride; + rct_ride_type *ride_type; rct_widget *dropdownWidget; - int i; + int i, j, num_items; + uint8 breakdownReason; + + dropdownWidget = widget; - if (widgetIndex != WIDX_INSPECTION_INTERVAL_DROPDOWN) - return; + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; - dropdownWidget = widget - 1; - rct_ride *ride = GET_RIDE(w->number); + switch (widgetIndex) { + case WIDX_INSPECTION_INTERVAL_DROPDOWN: + dropdownWidget--; + for (i = 0; i < 7; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_EVERY_10_MINUTES + i; + } + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + 7, + widget->right - dropdownWidget->left + ); - for (i = 0; i < 7; i++) { - gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = STR_EVERY_10_MINUTES + i; + gDropdownItemsChecked = (1 << ride->inspection_interval); + break; + + case WIDX_FORCE_BREAKDOWN: + num_items = 1; + for (j = 0; j < 3; j++) { + if (ride_type->ride_type[j] != 0xFF) + break; + } + gDropdownItemsFormat[0] = 1142; + gDropdownItemsArgs[0] = 5290; + for (i = 0; i < 8; i++) { + if (RideAvailableBreakdowns[ride_type->ride_type[j]] & (uint8)(1 << i)) { + if (i == BREAKDOWN_BRAKES_FAILURE && (ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED)) { + if (ride->num_vehicles != 1) + continue; + } + gDropdownItemsFormat[num_items] = 1142; + gDropdownItemsArgs[num_items] = STR_SAFETY_CUT_OUT + i; + num_items++; + } + } + if (num_items == 1) { + window_error_open(5289, STR_NONE); + } + else { + window_dropdown_show_text( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + num_items + ); + + num_items = 1; + breakdownReason = ride->breakdown_reason_pending; + if (breakdownReason != BREAKDOWN_NONE && (ride->lifecycle_flags & RIDE_LIFECYCLE_BREAKDOWN_PENDING)) { + for (i = 0; i < 8; i++) { + if (RideAvailableBreakdowns[ride_type->ride_type[j]] & (uint8)(1 << i)) { + if (i == BREAKDOWN_BRAKES_FAILURE && (ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED)) { + if (ride->num_vehicles != 1) + continue; + } + if (i == breakdownReason) { + gDropdownItemsChecked = (1 << num_items); + break; + } + gDropdownItemsFormat[num_items] = 1142; + gDropdownItemsArgs[num_items] = STR_SAFETY_CUT_OUT + i; + num_items++; + } + } + } + + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_BREAKDOWN_PENDING) == 0) { + *gDropdownItemsDisabled = (1 << 0); + } + } + break; } - window_dropdown_show_text_custom_width( - w->x + dropdownWidget->left, - w->y + dropdownWidget->top, - dropdownWidget->bottom - dropdownWidget->top + 1, - w->colours[1], - 0, - 7, - widget->right - dropdownWidget->left - ); - - gDropdownItemsChecked = (1 << ride->inspection_interval); + } /** @@ -3316,17 +3497,72 @@ static void window_ride_maintenance_dropdown() { rct_window *w; rct_ride *ride; + rct_ride_type *ride_type; + rct_vehicle *vehicle; short widgetIndex, dropdownIndex; + int i, j, num_items; window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex != WIDX_INSPECTION_INTERVAL_DROPDOWN || dropdownIndex == -1) + if (dropdownIndex == -1) return; - + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; + + switch (widgetIndex) { + case WIDX_INSPECTION_INTERVAL_DROPDOWN: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; + game_do_command(0, (dropdownIndex << 8) | 1, 0, (5 << 8) | w->number, GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + break; + + case WIDX_FORCE_BREAKDOWN: + if (dropdownIndex == 0) { + switch (ride->breakdown_reason_pending) { + case BREAKDOWN_RESTRAINTS_STUCK_CLOSED: + case BREAKDOWN_RESTRAINTS_STUCK_OPEN: + case BREAKDOWN_DOORS_STUCK_CLOSED: + case BREAKDOWN_DOORS_STUCK_OPEN: + vehicle = &(g_sprite_list[ride->vehicles[ride->broken_vehicle]].vehicle); + vehicle->var_48 &= ~0x100; + break; + case BREAKDOWN_VEHICLE_MALFUNCTION: + vehicle = &(g_sprite_list[ride->vehicles[ride->broken_vehicle]].vehicle); + vehicle->var_48 &= ~0x200; + break; + } + ride->lifecycle_flags &= ~(RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN); + window_invalidate_by_number(WC_RIDE, w->number); + break; + } + if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) { + window_error_open(5291, 5287); + } + else if (ride->status == RIDE_STATUS_CLOSED) { + window_error_open(5291, 5288); + } + else { + num_items = 1; + for (j = 0; j < 3; j++) { + if (ride_type->ride_type[j] != 0xFF) + break; + } + for (i = 0; i < 8; i++) { + if (RideAvailableBreakdowns[ride_type->ride_type[j]] & (uint8)(1 << i)) { + if (i == BREAKDOWN_BRAKES_FAILURE && (ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED)) { + if (ride->num_vehicles != 1) + continue; + } + if (num_items == dropdownIndex) + break; + num_items++; + } + } + ride_prepare_breakdown(w->number, i); + } + break; + } - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; - game_do_command(0, (dropdownIndex << 8) | 1, 0, (5 << 8) | w->number, GAME_COMMAND_11, 0, 0); } /** @@ -3338,12 +3574,12 @@ static void window_ride_maintenance_update(rct_window *w) rct_ride *ride; w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_4); ride = GET_RIDE(w->number); - if (ride->var_14D & 20) { - ride->var_14D &= ~20; + if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MAINTENANCE) { + ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_MAINTENANCE; window_invalidate(w); } } @@ -3358,6 +3594,7 @@ static void window_ride_maintenance_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -3375,6 +3612,14 @@ static void window_ride_maintenance_invalidate() window_ride_anchor_border_widgets(w); window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); + + if (gConfigGeneral.debugging_tools) { + window_ride_maintenance_widgets[WIDX_FORCE_BREAKDOWN].type = WWT_FLATBTN; + } + else { + window_ride_maintenance_widgets[WIDX_FORCE_BREAKDOWN].type = WWT_EMPTY; + + } } /** @@ -3416,13 +3661,12 @@ static void window_ride_maintenance_paint() x = w->x + widget->left + 4; y = w->y + widget->top + 4; - reliability = ride->var_196 >> 8; + reliability = ride->reliability >> 8; gfx_draw_string_left(dpi, STR_RELIABILITY_LABEL_1757, &reliability, 0, x, y); window_ride_maintenance_draw_bar(w, dpi, x + 103, y, max(10, reliability), 14); y += 11; - // Down time - downTime = ride->var_199; + downTime = ride->downtime; gfx_draw_string_left(dpi, STR_DOWN_TIME_LABEL_1889, &downTime, 0, x, y); window_ride_maintenance_draw_bar(w, dpi, x + 103, y, downTime, 28); y += 26; @@ -3491,7 +3735,6 @@ const uint8 window_ride_entrance_style_list[] = { RIDE_ENTRANCE_STYLE_CASTLE_GREY, RIDE_ENTRANCE_STYLE_LOG_CABIN, RIDE_ENTRANCE_STYLE_JUNGLE, - RIDE_ENTRANCE_STYLE_LOG_CABIN, RIDE_ENTRANCE_STYLE_CLASSICAL_ROMAN, RIDE_ENTRANCE_STYLE_ABSTRACT, RIDE_ENTRANCE_STYLE_SNOW_ICE, @@ -3507,12 +3750,11 @@ static uint32 window_ride_get_colour_button_image(int colour) static int window_ride_has_track_colour(rct_ride *ride, int trackColour) { uint16 unk_1 = RCT2_GLOBAL(0x00993E20 + (ride->entrance_style * 8), uint16); - uint32 unk_2 = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32); switch (trackColour) { - case 0: return ((unk_1 & 1) && !(unk_2 & 0x20000)) || (unk_2 & 1); - case 1: return ((unk_1 & 2) && !(unk_2 & 0x20000)) || (unk_2 & 2); - case 2: return unk_2 & 4; + case 0: return ((unk_1 & 1) && !ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) || ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_MAIN); + case 1: return ((unk_1 & 2) && !ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) || ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_ADDITIONAL); + case 2: return ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_SUPPORTS); default: return 0; } } @@ -3524,17 +3766,23 @@ static void window_ride_set_track_colour_scheme(rct_window *w, int x, int y) newColourScheme = (uint8)(*((uint16*)&w->var_494)); + int interactionType; + + rct_xy16 mapCoord = { 0 }; + get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_RIDE, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, NULL); + x = mapCoord.x; + y = mapCoord.y; // Get map coordinates from point - int eax, ebx, ecx, edx, esi, edi, ebp; + /*int eax, ebx, ecx, edx, esi, edi, ebp; eax = x; ebx = y; edx = -5; RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); x = eax & 0xFFFF; y = ecx & 0xFFFF; - mapElement = (rct_map_element*)edx; + mapElement = (rct_map_element*)edx;*/ - if ((ebx & 0xFF) != 3) + if (interactionType != VIEWPORT_INTERACTION_ITEM_RIDE) return; if (mapElement->properties.track.ride_index != w->number) return; @@ -3652,7 +3900,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0, + DROPDOWN_FLAG_STAY_OPEN, 4, widget->right - dropdownWidget->left ); @@ -3679,7 +3927,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0, + DROPDOWN_FLAG_STAY_OPEN, 4, widget->right - dropdownWidget->left ); @@ -3701,7 +3949,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, countof(window_ride_entrance_style_list), widget->right - dropdownWidget->left ); @@ -3719,8 +3967,8 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0, - rideEntry->var_010 > 1 ? 3 : 2, + DROPDOWN_FLAG_STAY_OPEN, + rideEntry->max_cars_in_train > 1 ? 3 : 2, widget->right - dropdownWidget->left ); @@ -3742,7 +3990,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0x80, + DROPDOWN_FLAG_STAY_OPEN, numItems, widget->right - dropdownWidget->left ); @@ -3784,22 +4032,22 @@ static void window_ride_colour_dropdown() window_invalidate(w); break; case WIDX_TRACK_MAIN_COLOUR: - game_do_command(0, (0 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + game_do_command(0, (0 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->var_494), 0); break; case WIDX_TRACK_ADDITIONAL_COLOUR: - game_do_command(0, (1 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + game_do_command(0, (1 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->var_494), 0); break; case WIDX_TRACK_SUPPORT_COLOUR: - game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->var_494), 0); break; case WIDX_MAZE_STYLE_DROPDOWN: - game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->var_494), 0); break; case WIDX_ENTRANCE_STYLE_DROPDOWN: - game_do_command(0, (6 << 8) | 1, 0, (window_ride_entrance_style_list[dropdownIndex] << 8) | w->number, GAME_COMMAND_0, 0, 0); + game_do_command(0, (6 << 8) | 1, 0, (window_ride_entrance_style_list[dropdownIndex] << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); break; case WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN: - game_do_command(0, (5 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, 0, 0); + game_do_command(0, (5 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); w->var_48C = 0; break; case WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN: @@ -3807,13 +4055,13 @@ static void window_ride_colour_dropdown() window_invalidate(w); break; case WIDX_VEHICLE_MAIN_COLOUR: - game_do_command(0, (2 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, w->var_48C, 0); + game_do_command(0, (2 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, w->var_48C, 0); break; case WIDX_VEHICLE_ADDITIONAL_COLOUR_1: - game_do_command(0, (3 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, w->var_48C, 0); + game_do_command(0, (3 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, w->var_48C, 0); break; case WIDX_VEHICLE_ADDITIONAL_COLOUR_2: - game_do_command(0, (7 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, w->var_48C, 0); + game_do_command(0, (7 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, w->var_48C, 0); break; } } @@ -3825,7 +4073,7 @@ static void window_ride_colour_dropdown() static void window_ride_colour_update(rct_window *w) { w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_5); widget_invalidate(w, WIDX_VEHICLE_PREVIEW); } @@ -3875,6 +4123,7 @@ static void window_ride_colour_invalidate() int vehicleColourSchemeType; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -3905,7 +4154,7 @@ static void window_ride_colour_invalidate() } // Track, multiple colour schemes - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x80000000) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SUPPORTS_MULTIPLE_TRACK_COLOUR)) { window_ride_colour_widgets[WIDX_TRACK_COLOUR_SCHEME].type = WWT_DROPDOWN; window_ride_colour_widgets[WIDX_TRACK_COLOUR_SCHEME_DROPDOWN].type = WWT_DROPDOWN_BUTTON; window_ride_colour_widgets[WIDX_PAINT_INDIVIDUAL_AREA].type = WWT_FLATBTN; @@ -3940,7 +4189,7 @@ static void window_ride_colour_invalidate() } // Track preview - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 7) + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_MAIN | RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_ADDITIONAL | RIDE_TYPE_FLAG_HAS_TRACK_COLOUR_SUPPORTS)) window_ride_colour_widgets[WIDX_TRACK_PREVIEW].type = WWT_SPINNER; else window_ride_colour_widgets[WIDX_TRACK_PREVIEW].type = WWT_EMPTY; @@ -3959,10 +4208,7 @@ static void window_ride_colour_invalidate() } // Vehicle colours - if ( - !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) && - (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x4000000) - ) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_13) && ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_26)) { vehicleColourSchemeType = ride->colour_scheme_type & 3; if (vehicleColourSchemeType == 0) w->var_48C = 0; @@ -3978,9 +4224,9 @@ static void window_ride_colour_invalidate() uint8 *unk; uint32 unk_eax = 0; for (unk = (uint8*)0x00F64E38; *unk != 0xFF; unk++) { - unk_eax |= RCT2_GLOBAL((int)rideEntry + 0x2E + (*unk * 101), uint16); + unk_eax |= rideEntry->vehicles[*unk].var_14; unk_eax = ror32(unk_eax, 16); - unk_eax |= RCT2_GLOBAL((int)rideEntry + 0x2C + (*unk * 101), uint16); + unk_eax |= rideEntry->vehicles[*unk].var_12; unk_eax = ror32(unk_eax, 16); } @@ -4000,10 +4246,7 @@ static void window_ride_colour_invalidate() } // Vehicle colour scheme type - if ( - !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x10000) && - (ride->num_cars_per_train | ride->num_vehicles) > 1 - ) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_16) && (ride->num_cars_per_train | ride->num_vehicles) > 1) { window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME].type = WWT_DROPDOWN; window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN].type = WWT_DROPDOWN_BUTTON; } else { @@ -4118,7 +4361,7 @@ static void window_ride_colour_paint() spriteIndex = (trackColour.additional << 24) | (trackColour.main << 19); spriteIndex |= 0xA0000000; - spriteIndex += RCT2_GLOBAL(0x00993E7C + (ride->entrance_style * 8), uint32); + spriteIndex += RideEntranceDefinitions[ride->entrance_style].spriteIndex; // Back gfx_draw_sprite(clippedDpi, spriteIndex, 34, 20, terniaryColour); @@ -4129,6 +4372,8 @@ static void window_ride_colour_paint() // ? if (terniaryColour != 0) gfx_draw_sprite(clippedDpi, ((spriteIndex + 20) & 0x7FFFF) + terniaryColour, 34, 20, terniaryColour); + + rct2_free(clippedDpi); } } } @@ -4144,7 +4389,6 @@ static void window_ride_colour_scrollpaint() rct_ride *ride; rct_ride_type *rideEntry; rct_widget *vehiclePreviewWidget; - uint8 *unk; int colour, x, y, spriteIndex; vehicle_colour vehicleColour; @@ -4165,17 +4409,17 @@ static void window_ride_colour_scrollpaint() // ? colour = (ride->colour_scheme_type & 3) == RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR ? - w->var_48C : rideEntry->var_013; - colour = RCT2_ADDRESS(0x00F64E38, uint8)[colour]; - unk = (uint8*)rideEntry + (colour * 101); + w->var_48C : rideEntry->tab_vehicle; - y += RCT2_GLOBAL(unk + 0x24, sint8); + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[colour]]; + + y += rideVehicleEntry->var_0A; // Draw the coloured spinning vehicle - spriteIndex = RCT2_GLOBAL(unk + 0x2C, uint8) & 0x800 ? w->frame_no / 4 : w->frame_no / 2; - spriteIndex &= RCT2_GLOBAL(unk + 0x1A, uint16); - spriteIndex *= RCT2_GLOBAL(unk + 0x30, uint16); - spriteIndex += RCT2_GLOBAL(unk + 0x32, uint32); + spriteIndex = rideVehicleEntry->var_12 & 0x800 ? w->frame_no / 4 : w->frame_no / 2; + spriteIndex &= rideVehicleEntry->var_00; + spriteIndex *= rideVehicleEntry->var_16; + spriteIndex += rideVehicleEntry->base_image_id; spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); spriteIndex |= 0x80000000; gfx_draw_sprite(dpi, spriteIndex, x, y, vehicleColour.additional_2); @@ -4230,7 +4474,7 @@ static void window_ride_toggle_music(rct_window *w) int activateMusic = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) ? 0 : 1; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; - game_do_command(0, (activateMusic << 8) | 1, 0, (6 << 8) | w->number, GAME_COMMAND_11, 0, 0); + game_do_command(0, (activateMusic << 8) | 1, 0, (6 << 8) | w->number, GAME_COMMAND_SET_RIDE_SETTING, 0, 0); } /** @@ -4302,27 +4546,30 @@ static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widg for (i = 0; i < countof(MusicStyleOrder); i++) window_ride_current_music_style_order[numItems++] = MusicStyleOrder[i]; - if (RCT2_GLOBAL(0x009AF164, uint32) != 0) + if (ride_music_info_list[36]->length != 0) window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_CUSTOM_MUSIC_1; - if (RCT2_GLOBAL(0x009AF16E, uint32) != 0) + if (ride_music_info_list[37]->length != 0) window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_CUSTOM_MUSIC_2; } + for (i = 0; i < numItems; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_MUSIC_STYLE_START + window_ride_current_music_style_order[i]; + } + window_dropdown_show_text_custom_width( w->x + dropdownWidget->left, w->y + dropdownWidget->top, dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], - 0, + DROPDOWN_FLAG_STAY_OPEN, numItems, widget->right - dropdownWidget->left ); for (i = 0; i < numItems; i++) { - gDropdownItemsFormat[i] = 1142; if (window_ride_current_music_style_order[i] == ride->music) gDropdownItemsChecked = (1 << i); - gDropdownItemsArgs[i] = STR_MUSIC_STYLE_START + window_ride_current_music_style_order[i]; } } @@ -4345,7 +4592,7 @@ static void window_ride_music_dropdown() ride = GET_RIDE(w->number); musicStyle = window_ride_current_music_style_order[dropdownIndex]; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; - game_do_command(0, (musicStyle << 8) | 1, 0, (7 << 8) | w->number, GAME_COMMAND_11, 0, 0); + game_do_command(0, (musicStyle << 8) | 1, 0, (7 << 8) | w->number, GAME_COMMAND_SET_RIDE_SETTING, 0, 0); } /** @@ -4355,7 +4602,7 @@ static void window_ride_music_dropdown() static void window_ride_music_update(rct_window *w) { w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_6); } @@ -4370,6 +4617,7 @@ static void window_ride_music_invalidate() int isMusicActivated; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -4421,13 +4669,57 @@ static void window_ride_music_paint() #pragma region Measurements +/* rct2: 0x006D2804 when al == 0*/ +static void cancel_scenery_selection(){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) &= ~(1 << 2); + RCT2_GLOBAL(0x9DEA6F, uint8) &= ~(1 << 0); + unpause_sounds(); + + rct_window* main_w = window_get_main(); + + if (main_w){ + main_w->viewport->flags &= ~(VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE); + } + + gfx_invalidate_screen(); + tool_cancel(); +} + +/* rct2: 0x006D27A3 */ +static void setup_scenery_selection(rct_window* w){ + rct_ride* ride = GET_RIDE(w->number); + + if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1){ + cancel_scenery_selection(); + } + + while (tool_set(w, 0, 12)); + + RCT2_GLOBAL(0x00F64DE8, uint8) = (uint8)w->number; + RCT2_GLOBAL(0x009DA193, uint8) = 0xFF; + + RCT2_GLOBAL(0x00F63674, sint32) = -1; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) |= (1 << 2); + RCT2_GLOBAL(0x009DEA6F, uint8) |= 1; + + pause_sounds(); + + rct_window* w_main = window_get_main(); + + if (w_main){ + w_main->viewport->flags |= (VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE); + } + + gfx_invalidate_screen(); +} + /** * * rct2: 0x006D3026 */ static void window_ride_measurements_design_reset() { - RCT2_CALLPROC_EBPSAFE(0x006D3026); + track_save_reset_scenery(); } /** @@ -4436,16 +4728,7 @@ static void window_ride_measurements_design_reset() */ static void window_ride_measurements_design_select_nearby_scenery() { - RCT2_CALLPROC_EBPSAFE(0x006D303D); -} - -/** - * - * rct2: 0x006AD4CD - */ -static void window_ride_measurements_design_save(rct_window *w) -{ - RCT2_CALLPROC_X(0x006D2804, 1, 0, 0, 0, (int)w, 0, 0); + track_save_select_nearby_scenery(RCT2_GLOBAL(0x00F64DE8, uint8)); } /** @@ -4455,7 +4738,18 @@ static void window_ride_measurements_design_save(rct_window *w) static void window_ride_measurements_design_cancel() { if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1) - RCT2_CALLPROC_X(0x006D2804, 0, 0, 0, 0, 0, 0, 0); + cancel_scenery_selection(); +} + +/** + * + * rct2: 0x006AD4CD + */ +static void window_ride_measurements_design_save(rct_window *w) +{ + if (save_track_design((uint8)w->number) == 0) return; + + window_ride_measurements_design_cancel(); } /** @@ -4567,9 +4861,9 @@ static void window_ride_measurements_dropdown() dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); if (dropdownIndex == 0) - RCT2_CALLPROC_X(0x006D264D, 0, 0, 0, 0, (int)w, 0, 0); + save_track_design((uint8)w->number); else - RCT2_CALLPROC_X(0x006D27A3, 0, 0, 0, 0, (int)w, 0, 0); + setup_scenery_selection(w); } /** @@ -4579,7 +4873,7 @@ static void window_ride_measurements_dropdown() static void window_ride_measurements_update(rct_window *w) { w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_7); } @@ -4616,6 +4910,7 @@ static void window_ride_measurements_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -4641,8 +4936,8 @@ static void window_ride_measurements_invalidate() window_ride_measurements_widgets[WIDX_RESET_SELECTION].type = WWT_EMPTY; window_ride_measurements_widgets[WIDX_SAVE_DESIGN].type = WWT_EMPTY; window_ride_measurements_widgets[WIDX_CANCEL_DESIGN].type = WWT_EMPTY; - if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_19)) { - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x10000000) { + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS)) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) { window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].type = WWT_FLATBTN; w->disabled_widgets |= (1 << WIDX_SAVE_TRACK_DESIGN); if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) { @@ -4692,7 +4987,7 @@ static void window_ride_measurements_paint() } else { ride = GET_RIDE(w->number); - if (ride->lifecycle_flags & RIDE_LIFECYCLE_19) + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) gfx_draw_sprite(dpi, 23225, w->x + w->width - 53, w->y + w->height - 73, 0); x = w->x + window_ride_measurements_widgets[WIDX_PAGE_BACKGROUND].left + 4; @@ -4794,7 +5089,7 @@ static void window_ride_measurements_paint() gfx_draw_string_left_clipped(dpi, STR_RIDE_LENGTH, (void*)0x013CE952, 0, x, y, 308); y += 10; - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x80) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) { // Max. positive vertical G's maxPositiveVerticalGs = ride->max_positive_vertical_g; stringId = maxPositiveVerticalGs >= FIXED_2DP(5,00) ? @@ -4822,7 +5117,7 @@ static void window_ride_measurements_paint() y += 10; } - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x400) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DROPS)) { // Drops drops = ride->drops & 0x3F; gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y); @@ -4951,9 +5246,9 @@ static void window_ride_graphs_update(rct_window *w) int x; w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_8); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_GRAPH); widget = &window_ride_graphs_widgets[WIDX_GRAPH]; @@ -4981,7 +5276,7 @@ static void window_ride_graphs_scrollgetheight() window_get_register(w); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); // Set minimum size width = window_ride_graphs_widgets[WIDX_GRAPH].right - window_ride_graphs_widgets[WIDX_GRAPH].left - 2; @@ -4992,18 +5287,7 @@ static void window_ride_graphs_scrollgetheight() if (measurement != NULL) width = max(width, measurement->num_items); - // Return size - #ifdef _MSC_VER - __asm mov ecx, width - #else - __asm__ ( "mov ecx, 0 " ); - #endif - - #ifdef _MSC_VER - __asm mov edx, height - #else - __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); - #endif + window_scrollsize_set_registers(width, height); } /** @@ -5026,12 +5310,12 @@ static void window_ride_graphs_15() static void window_ride_graphs_tooltip() { rct_window *w; - short unused, widgetIndex, result; + short widgetIndex, result; rct_ride *ride; rct_ride_measurement *measurement; rct_string_id stringId; - window_dropdown_get_registers(w, unused, widgetIndex); + window_tooltip_get_registers(w, widgetIndex); result = -1; if (widgetIndex == WIDX_GRAPH) { @@ -5047,11 +5331,7 @@ static void window_ride_graphs_tooltip() } } - #ifdef _MSC_VER - __asm mov ax, result - #else - __asm__ ( "mov ax, %[result] " : [result] "+m" (result) ); - #endif + window_tooltip_set_registers(result); } /** @@ -5066,6 +5346,7 @@ static void window_ride_graphs_invalidate() int x, y; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -5088,7 +5369,7 @@ static void window_ride_graphs_invalidate() w->pressed_widgets |= (1LL << (WIDX_GRAPH_VELOCITY + (w->list_information_type & 0xFF))); // Hide graph buttons that are not applicable - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x80) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) { window_ride_graphs_widgets[WIDX_GRAPH_VERTICAL].type = WWT_DROPDOWN_BUTTON; window_ride_graphs_widgets[WIDX_GRAPH_LATERAL].type = WWT_DROPDOWN_BUTTON; } else { @@ -5197,11 +5478,12 @@ static void window_ride_graphs_scrollpaint() gfx_fill_rect(dpi, dpi->x, y, dpi->x + dpi->width - 1, y, colour); + sint16 scaled_yUnit = yUnit; // Scale modifier if (ax == 1420) - yUnit /= 2; + scaled_yUnit /= 2; - gfx_draw_string_left(dpi, ax, &yUnit, 0, w->scrolls[0].h_left + 1, y - 4); + gfx_draw_string_left(dpi, ax, &scaled_yUnit, 0, w->scrolls[0].h_left + 1, y - 4); } // Time marks @@ -5259,7 +5541,45 @@ static void window_ride_graphs_scrollpaint() */ static void window_ride_income_toggle_primary_price(rct_window *w) { - RCT2_CALLPROC_X(0x006ADEFD, 0, 0, 0, 0, (int)w, 0, 0); + rct_ride *ride; + rct_ride_type *ride_type; + uint32 newFlags, shop_item; + money16 price; + + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; + + if (ride->type == RIDE_TYPE_TOILETS) { + shop_item = 0x1F; + } + else { + shop_item = ride_type->shop_item; + if (shop_item == 0xFFFF) + return; + } + if (shop_item == 0x3 || shop_item == 0x20 || shop_item == 0x21 || shop_item == 0x22) { + newFlags = RCT2_GLOBAL(0x01358838, uint32); + newFlags ^= (1 << 0x3); + game_do_command(0, 1, 0, (0x2 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + + newFlags = RCT2_GLOBAL(0x0135934C, uint32); + newFlags ^= (1 << 0x0) | (1 << 0x1) | (1 << 0x2); + game_do_command(0, 1, 0, (0x3 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + } + else { + if (shop_item < 32) { + newFlags = RCT2_GLOBAL(0x01358838, uint32); + newFlags ^= (1 << shop_item); + game_do_command(0, 1, 0, (0x2 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + } + else { + newFlags = RCT2_GLOBAL(0x0135934C, uint32); + newFlags ^= (1 << (shop_item - 32)); + game_do_command(0, 1, 0, (0x3 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + } + } + price = ride->price; + game_do_command(0, 1, 0, w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0); } /** @@ -5268,7 +5588,41 @@ static void window_ride_income_toggle_primary_price(rct_window *w) */ static void window_ride_income_toggle_secondary_price(rct_window *w) { - RCT2_CALLPROC_X(0x006AE06E, 0, 0, 0, 0, (int)w, 0, 0); + rct_ride *ride; + rct_ride_type *ride_type; + uint32 newFlags, shop_item; + money16 price; + + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; + + shop_item = ride_type->shop_item_secondary; + if (shop_item == 0xFF) + shop_item = RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8); + + if (shop_item == 0x3 || shop_item == 0x20 || shop_item == 0x21 || shop_item == 0x22) { + newFlags = RCT2_GLOBAL(0x01358838, uint32); + newFlags ^= (1 << 0x3); + game_do_command(0, 1, 0, (0x2 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + + newFlags = RCT2_GLOBAL(0x0135934C, uint32); + newFlags ^= (1 << 0x0) | (1 << 0x1) | (1 << 0x2); + game_do_command(0, 1, 0, (0x3 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + } + else { + if (shop_item < 32) { + newFlags = RCT2_GLOBAL(0x01358838, uint32); + newFlags ^= (1 << shop_item); + game_do_command(0, 1, 0, (0x2 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + } + else { + newFlags = RCT2_GLOBAL(0x0135934C, uint32); + newFlags ^= (1 << (shop_item - 32)); + game_do_command(0, 1, 0, (0x3 << 8), GAME_COMMAND_SET_PARK_OPEN, newFlags, shop_item); + } + } + price = ride->price_secondary; + game_do_command(0, 1, 0, (1 << 8) | w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0); } /** @@ -5277,7 +5631,23 @@ static void window_ride_income_toggle_secondary_price(rct_window *w) */ static void window_ride_income_increase_primary_price(rct_window *w) { - RCT2_CALLPROC_X(0x006AE1E4, 0, 0, 0, 0, (int)w, 0, 0); + rct_ride *ride; + rct_ride_type *ride_type; + + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; + + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) == 0) { + if (ride->type != RIDE_TYPE_TOILETS && ride_type->shop_item == 0xFF) { + if (!gConfigCheat.unlock_all_prices) + return; + } + } + money16 price = ride->price; + if (price < MONEY(20, 00)) + price++; + + game_do_command(0, 1, 0, w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0); } /** @@ -5286,7 +5656,23 @@ static void window_ride_income_increase_primary_price(rct_window *w) */ static void window_ride_income_decrease_primary_price(rct_window *w) { - RCT2_CALLPROC_X(0x006AE237, 0, 0, 0, 0, (int)w, 0, 0); + rct_ride *ride; + rct_ride_type *ride_type; + + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; + + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) == 0) { + if (ride->type != RIDE_TYPE_TOILETS && ride_type->shop_item == 0xFF) { + if (!gConfigCheat.unlock_all_prices) + return; + } + } + money16 price = ride->price; + if (price > MONEY(0, 00)) + price--; + + game_do_command(0, 1, 0, w->number, GAME_COMMAND_SET_RIDE_PRICE, price, 0); } /** @@ -5295,7 +5681,23 @@ static void window_ride_income_decrease_primary_price(rct_window *w) */ static void window_ride_income_increase_secondary_price(rct_window *w) { - RCT2_CALLPROC_X(0x006AE269, 0, 0, 0, 0, (int)w, 0, 0); + rct_ride *ride; + rct_ride_type *ride_type; + + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; + + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) == 0) { + if (ride->type != RIDE_TYPE_TOILETS && ride_type->shop_item_secondary == 0xFF) { + if (!gConfigCheat.unlock_all_prices) + return; + } + } + money16 price = ride->price_secondary; + if (price < MONEY(20, 00)) + price++; + + game_do_command(0, 1, 0, (w->number & 0x00FF) | 0x0100, GAME_COMMAND_SET_RIDE_PRICE, price, 0); } /** @@ -5304,7 +5706,23 @@ static void window_ride_income_increase_secondary_price(rct_window *w) */ static void window_ride_income_decrease_secondary_price(rct_window *w) { - RCT2_CALLPROC_X(0x006AE28D, 0, 0, 0, 0, (int)w, 0, 0); + rct_ride *ride; + rct_ride_type *ride_type; + + ride = GET_RIDE(w->number); + ride_type = gRideTypeList[ride->subtype]; + + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) == 0) { + if (ride->type != RIDE_TYPE_TOILETS && ride_type->shop_item_secondary == 0xFF) { + if (!gConfigCheat.unlock_all_prices) + return; + } + } + money16 price = ride->price_secondary; + if (price > MONEY(0, 00)) + price--; + + game_do_command(0, 1, 0, (w->number & 0x00FF) | 0x0100, GAME_COMMAND_SET_RIDE_PRICE, price, 0); } /** @@ -5387,12 +5805,12 @@ static void window_ride_income_update(rct_window *w) rct_ride *ride; w->frame_no++; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_9); ride = GET_RIDE(w->number); - if (ride->var_14D & 2) { - ride->var_14D &= ~2; + if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_INCOME) { + ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_INCOME; window_invalidate(w); } } @@ -5410,6 +5828,7 @@ static void window_ride_income_invalidate() int primaryItem, secondaryItem; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -5428,11 +5847,11 @@ static void window_ride_income_invalidate() // Primary item w->pressed_widgets &= ~(1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); w->disabled_widgets &= ~(1 << WIDX_PRIMARY_PRICE); - if ( - !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) && - rideEntry->shop_item == 255 && - ride->type != RIDE_TYPE_BATHROOM - ) { + + //If the park doesn't have free entry, lock the admission price, unless the cheat to unlock all prices is activated. + if ((!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) && rideEntry->shop_item == 255 && ride->type != RIDE_TYPE_TOILETS) + && (!gConfigCheat.unlock_all_prices)) + { w->disabled_widgets |= (1 << WIDX_PRIMARY_PRICE); } @@ -5446,23 +5865,23 @@ static void window_ride_income_invalidate() window_ride_income_widgets[WIDX_PRIMARY_PRICE].image = STR_FREE; primaryItem = 31; - if (ride->type != RIDE_TYPE_BATHROOM) { - if ((primaryItem = (sint8)rideEntry->shop_item) != -1) { - window_ride_income_widgets[WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK].type = WWT_CHECKBOX; - if (primaryItem < 32) { - if (RCT2_GLOBAL(0x01358838, uint32) & (1 << primaryItem)) - w->pressed_widgets |= (1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); + if (ride->type == RIDE_TYPE_TOILETS || ((primaryItem = (sint8)rideEntry->shop_item) != -1)) { + window_ride_income_widgets[WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK].type = WWT_CHECKBOX; + if (primaryItem < 32) { + if (RCT2_GLOBAL(0x01358838, uint32) & (1 << primaryItem)) + w->pressed_widgets |= (1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); - if (primaryItem != 31) - window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = 1960 + primaryItem; - } else { - primaryItem -= 32; - if (RCT2_GLOBAL(0x0135934C, uint32) & (1 << primaryItem)) - w->pressed_widgets |= (1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); - - window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = 2100 + primaryItem; - } + if (primaryItem != 31) + window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = 1960 + primaryItem; } + else { + primaryItem -= 32; + if (RCT2_GLOBAL(0x0135934C, uint32) & (1 << primaryItem)) + w->pressed_widgets |= (1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); + + window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = 2100 + primaryItem; + } + } // Get secondary item @@ -5493,7 +5912,7 @@ static void window_ride_income_invalidate() w->pressed_widgets |= (1 << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK); } else { secondaryItem -= 32; - if (RCT2_GLOBAL(0x0135884C, uint32) & (1 << secondaryItem)) + if (RCT2_GLOBAL(0x0135934C, uint32) & (1 << secondaryItem)) w->pressed_widgets |= (1 << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK); } @@ -5567,9 +5986,9 @@ static void window_ride_income_paint() profit = ride->price_secondary; stringId = STR_PROFIT_PER_ITEM_SOLD; - profit -= primaryItem < 32 ? - RCT2_GLOBAL(0x00982164 + (primaryItem * 8), uint16) : - RCT2_GLOBAL(0x00982144 + (primaryItem * 8), uint16); + profit -= secondaryItem < 32 ? + RCT2_GLOBAL(0x00982164 + (secondaryItem * 8), uint16) : + RCT2_GLOBAL(0x00982144 + (secondaryItem * 8), uint16); if (profit < 0) { profit *= -1; stringId = STR_LOSS_PER_ITEM_SOLD; @@ -5634,13 +6053,13 @@ static void window_ride_customer_mouseup() window_ride_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_SHOW_GUESTS_THOUGHTS: - RCT2_CALLPROC_X(0x006993BA, 2, w->number, 0, 0, 0, 0, 0); + window_guest_list_open_with_filter(2, w->number); break; case WIDX_SHOW_GUESTS_ON_RIDE: - RCT2_CALLPROC_X(0x006993BA, 0, w->number, 0, 0, 0, 0, 0); + window_guest_list_open_with_filter(0, w->number); break; case WIDX_SHOW_GUESTS_QUEUING: - RCT2_CALLPROC_X(0x006993BA, 1, w->number, 0, 0, 0, 0, 0); + window_guest_list_open_with_filter(1, w->number); break; } } @@ -5671,12 +6090,12 @@ static void window_ride_customer_update(rct_window *w) if (w->var_492 >= 24) w->var_492 = 0; - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); widget_invalidate(w, WIDX_TAB_10); ride = GET_RIDE(w->number); - if (ride->var_14D & 1) { - ride->var_14D &= ~1; + if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_CUSTOMER) { + ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_CUSTOMER; window_invalidate(w); } } @@ -5691,6 +6110,7 @@ static void window_ride_customer_invalidate() rct_widget *widgets; window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; if (w->widgets != widgets) { @@ -5704,13 +6124,13 @@ static void window_ride_customer_invalidate() RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; - if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) * 0x20000) { - window_ride_customer_widgets[WIDX_SHOW_GUESTS_THOUGHTS].type = WWT_FLATBTN; - window_ride_customer_widgets[WIDX_SHOW_GUESTS_ON_RIDE].type = WWT_FLATBTN; - window_ride_customer_widgets[WIDX_SHOW_GUESTS_QUEUING].type = WWT_FLATBTN; - } else { + window_ride_customer_widgets[WIDX_SHOW_GUESTS_THOUGHTS].type = WWT_FLATBTN; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) { window_ride_customer_widgets[WIDX_SHOW_GUESTS_ON_RIDE].type = WWT_EMPTY; window_ride_customer_widgets[WIDX_SHOW_GUESTS_QUEUING].type = WWT_EMPTY; + } else { + window_ride_customer_widgets[WIDX_SHOW_GUESTS_ON_RIDE].type = WWT_FLATBTN; + window_ride_customer_widgets[WIDX_SHOW_GUESTS_QUEUING].type = WWT_FLATBTN; } window_ride_anchor_border_widgets(w); @@ -5749,7 +6169,7 @@ static void window_ride_customer_paint() y += 10; // Popularity - popularity = ride->var_158 & 0xFF; + popularity = ride->popularity; if (popularity == 255) { stringId = STR_POPULARITY_UNKNOWN; } else { @@ -5760,7 +6180,7 @@ static void window_ride_customer_paint() y += 10; // Satisfaction - satisfaction = ride->var_14A & 0xFF; + satisfaction = ride->satisfaction; if (satisfaction == 255) { stringId = STR_SATISFACTION_UNKNOWN; } else { @@ -5784,7 +6204,7 @@ static void window_ride_customer_paint() stringId += 96; RCT2_GLOBAL(0x013CE952 + 0, uint16) = stringId; - RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->var_1A4; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->no_primary_items_sold; gfx_draw_string_left(dpi, STR_ITEMS_SOLD, (void*)0x013CE952, 0, x, y); y += 10; } @@ -5799,7 +6219,7 @@ static void window_ride_customer_paint() stringId += 96; RCT2_GLOBAL(0x013CE952 + 0, uint16) = stringId; - RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->var_1A4; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->no_secondary_items_sold; gfx_draw_string_left(dpi, STR_ITEMS_SOLD, (void*)0x013CE952, 0, x, y); y += 10; } @@ -5819,7 +6239,8 @@ static void window_ride_customer_paint() y += 2; // Age - age = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) - ride->build_date) / 8; + //If the ride has a build date that is in the future, show it as built this year. + age = max((RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) - ride->build_date) / 8, 0); stringId = age == 0 ? STR_BUILT_THIS_YEAR : age == 1 ? @@ -5828,4 +6249,4 @@ static void window_ride_customer_paint() gfx_draw_string_left(dpi, stringId, &age, 0, x, y); } -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/windows/ride_construction.c b/src/windows/ride_construction.c index 2e9a31a637..7cb6c54658 100644 --- a/src/windows/ride_construction.c +++ b/src/windows/ride_construction.c @@ -8,12 +8,12 @@ * 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 . *****************************************************************************/ @@ -22,6 +22,9 @@ #include "../interface/window.h" #include "../interface/viewport.h" #include "../game.h" +#include "../ride/track.h" +#include "../drawing/drawing.h" +#include "../interface/themes.h" /* move to ride.c */ void sub_6b2fa9(rct_windownumber number){ @@ -35,10 +38,23 @@ void sub_6b2fa9(rct_windownumber number){ } } +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PAGE_BACKGROUND, + + WIDX_DEMOLISH = 24 +}; + void window_construction_emptysub(){} void window_construction_close(); +void window_construction_mouseup(); +void window_construction_paint(); void window_construction_maze_close(); +void window_construction_maze_invalidate(); +void window_construction_maze_paint(); // 0x993F6C static void* window_construction_maze_events[] = { @@ -67,18 +83,18 @@ static void* window_construction_maze_events[] = { window_construction_emptysub, window_construction_emptysub, window_construction_emptysub, - (void*)0x6CD435, - (void*)0x6CD45B, + window_construction_maze_invalidate, + window_construction_maze_paint, window_construction_emptysub }; //0x993EEC static void* window_construction_events[] = { window_construction_close, - (void*)0x6C6E14, + window_construction_mouseup, (void*)0x6C7934, (void*)0x6C6E6A, - window_construction_emptysub, + (void*)0x6C78CD, window_construction_emptysub, (void*)0x6C8374, window_construction_emptysub, @@ -100,18 +116,16 @@ static void* window_construction_events[] = { window_construction_emptysub, window_construction_emptysub, (void*)0x6C6AD5, - (void*)0x6C6B86, + window_construction_paint,//(void*)0x6C6B86, window_construction_emptysub }; /** - * + * * rct2: 0x006CB481 */ rct_window *window_construction_open() { - int eax, ebx, ecx, edx, esi, edi, ebp; - int ride_id = RCT2_GLOBAL(0xF440A7, uint8); sub_6b2fa9(ride_id); @@ -125,9 +139,7 @@ rct_window *window_construction_open() window_init_scroll_widgets(w); - w->colours[0] = 24; - w->colours[1] = 24; - w->colours[2] = 24; + colour_scheme_update(w); w->number = ride_id; @@ -152,7 +164,7 @@ rct_window *window_construction_open() window_push_others_right(w); show_gridlines(); - RCT2_GLOBAL(0xF44070, uint32) = 0x80000000; + RCT2_GLOBAL(0xF44070, uint32) = MONEY32_UNDEFINED; RCT2_GLOBAL(0xF440CD, uint8) = 8; RCT2_GLOBAL(0xF440CE, uint8) = 18; RCT2_GLOBAL(0xF440CF, uint8) = 4; @@ -165,7 +177,7 @@ rct_window *window_construction_open() RCT2_GLOBAL(0xF440CE, uint8) = 30; } - RCT2_GLOBAL(0xF440A0,uint16) = RCT2_ADDRESS(0x0097CC68, uint8)[ride->type * 2] | 0x100; + RCT2_GLOBAL(0xF440A0, uint16) = RCT2_ADDRESS(0x0097CC68, uint8)[ride->type * 2] | 0x100; RCT2_GLOBAL(0x00F440B2, uint8) = 0; RCT2_GLOBAL(0x00F440B3, uint8) = 0; RCT2_GLOBAL(0x00F440B4, uint8) = 0; @@ -177,46 +189,48 @@ rct_window *window_construction_open() RCT2_GLOBAL(0x00F440B6, uint8) = 0; RCT2_GLOBAL(0x00F440B7, uint8) = 0; - RCT2_GLOBAL(0x00F440AE, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = 0; RCT2_GLOBAL(0x00F440A6, uint8) = 4; RCT2_GLOBAL(0x00F440B0, uint8) = 0; RCT2_GLOBAL(0x00F440B1, uint8) = 0; RCT2_GLOBAL(0x00F44159, uint8) = 0; RCT2_GLOBAL(0x00F4415C, uint8) = 0; + colour_scheme_update(w); return w; - - RCT2_CALLFUNC_X(0x006CB481, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return (rct_window*)esi; } -void window_construction_close(){ +/* rct2: 0x006C845D */ +void window_construction_close() +{ rct_window *w; + rct_xy_element mapElement; window_get_register(w); - RCT2_CALLPROC_X(0x006C9627, 0, 0, 0, 0, 0, 0, 0); + sub_6C9627(); viewport_set_visibility(0); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); - RCT2_GLOBAL(0x9DE58A, uint16) &= 0xFFFD; + map_invalidate_map_selection_tiles(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 1); + + // In order to cancel the yellow arrow correctly the + // selection tool should be cancelled. + tool_cancel(); hide_gridlines(); - int x, y; - uint8 ride_id = RCT2_GLOBAL(0xF440A7, uint8); - rct_map_element* map_element = sub_6CAF80(ride_id, &x, &y); + uint8 rideIndex = RCT2_GLOBAL(0x00F440A7, uint8); + if (!sub_6CAF80(rideIndex, &mapElement)) { + int eax = RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8); - if ((int)map_element == -1){ - int eax = RCT2_GLOBAL(0x009DEA6E, uint8); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = 0; + game_do_command(0, 9, 0, rideIndex, GAME_COMMAND_7, 0, 0); - RCT2_GLOBAL(0x009DEA6E, uint8) = 0; - game_do_command(0, 9, 0, ride_id, GAME_COMMAND_7, 0, 0); - - RCT2_GLOBAL(0x009DEA6E, uint8) = eax; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = eax; return; } - window_ride_main_open(ride_id); + window_ride_main_open(rideIndex); } @@ -225,27 +239,221 @@ void window_construction_maze_close(){ window_get_register(w); - RCT2_CALLPROC_X(0x006C9627, 0, 0, 0, 0, 0, 0, 0); + sub_6C9627(); viewport_set_visibility(0); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); - RCT2_GLOBAL(0x9DE58A, uint16) &= 0xFFFD; + map_invalidate_map_selection_tiles(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 1); + + // In order to cancel the yellow arrow correctly the + // selection tool should be cancelled. + tool_cancel(); hide_gridlines(); - + uint8 ride_id = RCT2_GLOBAL(0xF440A7, uint8); rct_ride* ride = GET_RIDE(ride_id); if (ride->overall_view == 0xFFFF){ - int eax = RCT2_GLOBAL(0x009DEA6E, uint8); + int eax = RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8); - RCT2_GLOBAL(0x009DEA6E, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = 0; game_do_command(0, 9, 0, ride_id, GAME_COMMAND_7, 0, 0); - RCT2_GLOBAL(0x009DEA6E, uint8) = eax; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = eax; return; } window_ride_main_open(ride_id); +} + +void window_construction_mouseup_demolish(rct_window* w); + +/* rct2: 0x006C6E14 */ +void window_construction_mouseup(){ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + RCT2_CALLPROC_X(0x6C6A77, 0, 0, 0, 0, 0, 0, 0); + + switch (widgetIndex){ + case WIDX_CLOSE: + window_close(w); + break; + case 27: + RCT2_CALLPROC_X(0x6C9296, 0, 0, 0, widgetIndex, (int)w, 0, 0); + break; + case 26: + RCT2_CALLPROC_X(0x6C93B8, 0, 0, 0, widgetIndex, (int)w, 0, 0); + break; + case 23: + RCT2_CALLPROC_X(0x6C9F72, 0, 0, 0, widgetIndex, (int)w, 0, 0); + break; + case WIDX_DEMOLISH: + window_construction_mouseup_demolish(w); + break; + case 32: + RCT2_CALLPROC_X(0x6C78AA, 0, 0, 0, widgetIndex, (int)w, 0, 0); + break; + case 29: + RCT2_CALLPROC_X(0x6C7802, 0, 0, 0, widgetIndex, (int)w, 0, 0); + break; + case 30: + RCT2_CALLPROC_X(0x6C7866, 0, 0, 0, widgetIndex, (int)w, 0, 0); + break; + } +} + +/* rct2: 0x006C9BA5 */ +void window_construction_mouseup_demolish(rct_window* w){ + RCT2_CALLPROC_X(0x6C9BA5, 0, 0, 0, 0, (int)w, 0, 0); + return; + + RCT2_GLOBAL(0xF44070, uint32) = MONEY32_UNDEFINED; + sub_6C9627(); + + RCT2_GLOBAL(0xF440B8, uint8) = 3; + if (RCT2_GLOBAL(0xF440A6, uint8) == 1){ + //6C9C4F + } + + if (RCT2_GLOBAL(0xF440A6, uint8) != 2){ + //6c9cc4 + int eax = RCT2_GLOBAL(0xF440A8, uint16), + ebx = RCT2_GLOBAL(0xF440AF, uint8) || (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) << 8), + ecx = RCT2_GLOBAL(0xF440AA, uint16), + edx = RCT2_GLOBAL(0xF440AC, uint16); + + sub_6C683D(&eax, &ecx, &edx, RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8), RCT2_GLOBAL(0xF440AF, uint8) & 0x3FF, 0, 0, 0); + } + + int ride_id = RCT2_GLOBAL(0xF440A7, uint8); + RCT2_GLOBAL(0xF441D2, uint8) = ride_id; + //6c9BFE +} + +void window_construction_maze_invalidate() +{ + int ride_idx = RCT2_GLOBAL(0x00F440A7, uint8); + RCT2_GLOBAL(0x13CE958, uint32_t) = RCT2_GLOBAL(0x1362944 + ride_idx * 0x260, uint32_t); + RCT2_GLOBAL(0x13CE956, uint16_t) = RCT2_GLOBAL(0x1362942 + ride_idx * 0x260, uint16_t); +} + +//0x6C6B86 +void window_construction_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + window_paint_get_registers(w, dpi); + window_draw_widgets(w, dpi); + if (RCT2_GLOBAL(0x9D7C00, uint8_t) == 0) return; + uint32_t eax = 0, esi = (uint32_t)w, ebp = 0;//nothing + uint32_t ebx = 0, ecx = 0, edx = 0, edi = (uint32_t)dpi;//returns + if (RCT2_CALLFUNC_X(0x6CA2DF, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp) & 0x100) return; + RCT2_GLOBAL(0xF44133, uint8_t) = edx & 0xFF; + RCT2_GLOBAL(0xF44134, uint8_t) = (ebx >> 8) & 0xFF; + RCT2_GLOBAL(0xF44135, uint8_t) = (edx >> 8) & 0xFF; + edx >>= 16; + RCT2_GLOBAL(0xF44136, int16_t) = edx; + rct_ride* ride = GET_RIDE(RCT2_GLOBAL(0xF44133, uint8)); + RCT2_GLOBAL(0xF44064, uint32_t) = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32_t); + // 0x009D7C04 is a widget address remember to change when widget implemented + short width = RCT2_GLOBAL(0x9D7C04, int16_t) - RCT2_GLOBAL(0x9D7C02, int16_t) - 1; + short height = RCT2_GLOBAL(0x9D7C08, int16_t) - RCT2_GLOBAL(0x9D7C06, int16_t) - 1; + rct_drawpixelinfo* clip_dpi = clip_drawpixelinfo( + dpi, + // 0x009D7C02 is a widget address remember to change when widget implemented + w->x + RCT2_GLOBAL(0x9D7C02, int16_t) + 1, + width, + w->y + RCT2_GLOBAL(0x9D7C06, int16_t) + 1, + height); + if (clip_dpi != NULL) + { + rct_preview_track *trackBlock; + ecx = RCT2_GLOBAL(0xF44135, uint8_t); + if (RCT2_GLOBAL(0xF44064, uint32_t) & 0x80000) trackBlock = RCT2_ADDRESS(0x994A38, rct_preview_track*)[ecx];//RCT2_GLOBAL(0x994A38 + ecx * 4, rct_preview_track*); + else trackBlock = RCT2_ADDRESS(0x994638, rct_preview_track*)[ecx];//RCT2_GLOBAL(0x994638 + ecx * 4, rct_preview_track*); + while ((trackBlock + 1)->var_00 != 0xFF) trackBlock++; + short x = trackBlock->x; + short z = trackBlock->z; + short y = trackBlock->y; + if (trackBlock->var_09 & 2) x = y = 0; + short tmp; + switch (RCT2_GLOBAL(0xF44134, uint8_t) & 3) + { + case 1: + tmp = x; + x = y; + y = -tmp; + break; + case 2: + x = -x; + y = -y; + break; + case 3: + tmp = x; + x = -y; + y = tmp; + break; + case 0: + break; + } + //this is actually case 0, but the other cases all jump to it + x /= 2; + y /= 2; + x += 4112; + y += 4112; + z += 1024; + ebx = RCT2_GLOBAL(0xF44135, uint8_t); + short bx; + if (RCT2_GLOBAL(0xF44064, uint32_t) & 0x80000) bx = RCT2_GLOBAL(0x9984A2 + ebx * 8, sint8); + else bx = RCT2_GLOBAL(0x997CA2 + ebx * 8, sint8); + z -= bx; + int start_x = x; + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)) + { + case 0: + x = y - x; + y = (y + start_x) / 2 - z; + break; + case 1: + x = -x - y; + y = (y - start_x) / 2 - z; + break; + case 2: + x -= y; + y = (-y - start_x) / 2 - z; + break; + case 3: + x += y; + y = (-y + start_x) / 2 - z; + break; + } + clip_dpi->x += x - width / 2; + clip_dpi->y += y - height / 2 - 16; + RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*) = clip_dpi; + uint32_t d = RCT2_GLOBAL(0xF44136, int16_t) << 16; + d |= RCT2_GLOBAL(0xF44133, uint8_t);// Ride id + d |= RCT2_GLOBAL(0xF44135, uint8_t) << 8; + RCT2_CALLPROC_X(0x6CBCE2, 0x1000, (((uint16_t)bx) & 0xFF) | (RCT2_GLOBAL(0xF44134, uint8_t) << 8), 0x1000, d, width / 2, 0x400, height / 2); + rct2_free(clip_dpi); + } + short string_x = (RCT2_GLOBAL(0x9D7C02, int16_t) + RCT2_GLOBAL(0x9D7C04, int16_t)) / 2 + w->x; + short string_y = RCT2_GLOBAL(0x9D7C08, int16_t) + w->y - 23; + if (RCT2_GLOBAL(0xF440A6, uint8_t) != 4) gfx_draw_string_centred(dpi, 1407, string_x, string_y, 0, w); + string_y += 11; + if (RCT2_GLOBAL(0xF44070, uint32_t) != MONEY32_UNDEFINED && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32_t) & 0x800)) + gfx_draw_string_centred(dpi, 1408, string_x, string_y, 0, (void*)0xF44070); +} + +//0x006CD45B +void window_construction_maze_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + window_paint_get_registers(w, dpi); + window_draw_widgets(w, dpi); } \ No newline at end of file diff --git a/src/windows/ride_list.c b/src/windows/ride_list.c index d4e169c9bd..c70fb45ac0 100644 --- a/src/windows/ride_list.c +++ b/src/windows/ride_list.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../ride/ride.h" #include "../localisation/localisation.h" @@ -27,6 +28,7 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "dropdown.h" +#include "../interface/themes.h" enum { PAGE_RIDES, @@ -46,7 +48,9 @@ enum WINDOW_RIDE_LIST_WIDGET_IDX { WIDX_TAB_1, WIDX_TAB_2, WIDX_TAB_3, - WIDX_LIST + WIDX_LIST, + WIDX_CLOSE_LIGHT, + WIDX_OPEN_LIGHT }; static rct_widget window_ride_list_widgets[] = { @@ -62,6 +66,8 @@ static rct_widget window_ride_list_widgets[] = { { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_LIST_SHOPS_AND_STALLS_TIP }, // tab 2 { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_LIST_KIOSKS_AND_FACILITIES_TIP }, // tab 3 { WWT_SCROLL, 1, 3, 336, 60, 236, 2, 65535 }, // list + { WWT_IMGBTN, 1, 320, 333, 62, 75, SPR_G2_RCT1_CLOSE_BUTTON_0, STR_NONE }, + { WWT_IMGBTN, 1, 320, 333, 76, 89, SPR_G2_RCT1_OPEN_BUTTON_0, STR_NONE }, { WIDGETS_END }, }; @@ -140,7 +146,7 @@ void window_ride_list_open() // Check if window is already open window = window_bring_to_front_by_class(WC_RIDE_LIST); if (window == NULL) { - window = window_create_auto_pos(340, 240, (uint32*)window_ride_list_events, WC_RIDE_LIST, 0x0400); + window = window_create_auto_pos(340, 240, (uint32*)window_ride_list_events, WC_RIDE_LIST, WF_10 | WF_RESIZABLE); window->widgets = window_ride_list_widgets; window->enabled_widgets = (1 << WIDX_CLOSE) | @@ -150,7 +156,9 @@ void window_ride_list_open() (1 << WIDX_SORT) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | - (1 << WIDX_TAB_3); + (1 << WIDX_TAB_3) | + (1 << WIDX_CLOSE_LIGHT) | + (1 << WIDX_OPEN_LIGHT); window_init_scroll_widgets(window); window->page = PAGE_RIDES; window->no_list_items = 0; @@ -160,10 +168,6 @@ void window_ride_list_open() window->min_height = 240; window->max_width = 400; window->max_height = 450; - window->flags |= WF_RESIZABLE; - window->colours[0] = 1; - window->colours[1] = 26; - window->colours[2] = 26; } _window_ride_list_information_type = INFORMATION_TYPE_STATUS; window->list_information_type = 0; @@ -195,12 +199,19 @@ static void window_ride_list_mouseup() if (w->page != widgetIndex - WIDX_TAB_1) { w->page = widgetIndex - WIDX_TAB_1; w->no_list_items = 0; + w->frame_no = 0; w->selected_list_item = -1; if (w->page != PAGE_RIDES && _window_ride_list_information_type > INFORMATION_TYPE_PROFIT) _window_ride_list_information_type = INFORMATION_TYPE_PROFIT; window_invalidate(w); } break; + case WIDX_CLOSE_LIGHT: + window_ride_list_close_all(w); + break; + case WIDX_OPEN_LIGHT: + window_ride_list_open_all(w); + break; } } @@ -253,7 +264,15 @@ static void window_ride_list_mousedown(int widgetIndex, rct_window*w, rct_widget gDropdownItemsFormat[i] = 1142; gDropdownItemsArgs[i] = STR_STATUS + i; } - window_dropdown_show_text_custom_width(w->x + widget->left, w->y + widget->top, widget->bottom - widget->top, w->colours[1], 0x80, numItems, widget->right - widget->left - 3); + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + numItems, + widget->right - widget->left - 3 + ); gDropdownItemsChecked |= (1 << _window_ride_list_information_type); } } @@ -301,7 +320,7 @@ static void window_ride_list_update(rct_window *w) */ static void window_ride_list_scrollgetsize() { - int top, height; + int top, width, height; rct_window *w; window_get_register(w); @@ -320,18 +339,8 @@ static void window_ride_list_scrollgetsize() window_invalidate(w); } - #ifdef _MSC_VER - __asm mov ecx, 0 - #else - __asm__ ( "mov ecx, 0 " ); - #endif - - #ifdef _MSC_VER - __asm mov edx, height - #else - __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); - #endif - + width = 0; + window_scrollsize_set_registers(width, height); } /** @@ -341,10 +350,10 @@ static void window_ride_list_scrollgetsize() static void window_ride_list_scrollmousedown() { int index; - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items) @@ -361,10 +370,10 @@ static void window_ride_list_scrollmousedown() static void window_ride_list_scrollmouseover() { int index; - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items) @@ -391,8 +400,10 @@ static void window_ride_list_invalidate() { int i; rct_window *w; + rct_ride *ride; window_get_register(w); + colour_scheme_update(w); window_ride_list_widgets[WIDX_CURRENT_INFORMATION_TYPE].image = STR_STATUS + _window_ride_list_information_type; @@ -414,6 +425,38 @@ static void window_ride_list_invalidate() w->widgets[WIDX_LIST].bottom = w->height - 4; w->widgets[WIDX_OPEN_CLOSE_ALL].right = w->width - 2; w->widgets[WIDX_OPEN_CLOSE_ALL].left = w->width - 25; + w->widgets[WIDX_CLOSE_LIGHT].right = w->width - 7; + w->widgets[WIDX_CLOSE_LIGHT].left = w->width - 20; + w->widgets[WIDX_OPEN_LIGHT].right = w->width - 7; + w->widgets[WIDX_OPEN_LIGHT].left = w->width - 20; + + if (theme_get_preset()->features.rct1_ride_lights) { + w->widgets[WIDX_OPEN_CLOSE_ALL].type = WWT_EMPTY; + w->widgets[WIDX_CLOSE_LIGHT].type = WWT_IMGBTN; + w->widgets[WIDX_OPEN_LIGHT].type = WWT_IMGBTN; + + sint8 allClosed = -1; + sint8 allOpen = -1; + FOR_ALL_RIDES(i, ride) { + if (w->page != gRideClassifications[ride->type]) + continue; + if (ride->status == RIDE_STATUS_OPEN) { + if (allOpen == -1) allOpen = true; + allClosed = false; + } + else { + if (allClosed == -1) allClosed = true; + allOpen = false; + } + } + w->widgets[WIDX_CLOSE_LIGHT].image = SPR_G2_RCT1_CLOSE_BUTTON_0 + (allClosed == 1) * 2 + widget_is_pressed(w, WIDX_CLOSE_LIGHT); + w->widgets[WIDX_OPEN_LIGHT].image = SPR_G2_RCT1_OPEN_BUTTON_0 + (allOpen == 1) * 2 + widget_is_pressed(w, WIDX_OPEN_LIGHT); + } + else { + w->widgets[WIDX_OPEN_CLOSE_ALL].type = WWT_FLATBTN; + w->widgets[WIDX_CLOSE_LIGHT].type = WWT_EMPTY; + w->widgets[WIDX_OPEN_LIGHT].type = WWT_EMPTY; + } } /** @@ -471,16 +514,16 @@ static void window_ride_list_scrollpaint() break; case INFORMATION_TYPE_POPULARITY: formatSecondary = STR_POPULARITY_UNKNOWN_LABEL; - if ((ride->var_158 & 0xFF) != 255) { + if (ride->popularity != 255) { formatSecondary = STR_POPULARITY_LABEL; - RCT2_GLOBAL(0x013CE952 + 2, uint16) = (ride->var_158 & 0xFF) * 4; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->popularity * 4; } break; case INFORMATION_TYPE_SATISFACTION: formatSecondary = STR_SATISFACTION_UNKNOWN_LABEL; - if ((ride->var_14A & 0xFF) != 255) { + if (ride->satisfaction != 255) { formatSecondary = STR_SATISFACTION_LABEL; - RCT2_GLOBAL(0x013CE952 + 2, uint16) = (ride->var_14A & 0xFF) * 5; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->satisfaction * 5; } break; case INFORMATION_TYPE_PROFIT: @@ -507,13 +550,13 @@ static void window_ride_list_scrollpaint() case INFORMATION_TYPE_RELIABILITY: // edx = RCT2_GLOBAL(0x009ACFA4 + (ride->var_001 * 4), uint32); - RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->var_196 >> 8; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->reliability >> 8; formatSecondary = STR_RELIABILITY_LABEL; break; case INFORMATION_TYPE_DOWN_TIME: // edx = RCT2_GLOBAL(0x009ACFA4 + (ride->var_001 * 4), uint32); - RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->var_199; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->downtime; formatSecondary = STR_DOWN_TIME_LABEL; break; case INFORMATION_TYPE_GUESTS_FAVOURITE: @@ -579,8 +622,8 @@ static void window_ride_list_refresh_list(rct_window *w) continue; countA++; - if (ride->var_14D & 8) { - ride->var_14D &= ~8; + if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_LIST) { + ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_LIST; countB++; } } @@ -616,7 +659,7 @@ static void window_ride_list_refresh_list(rct_window *w) case INFORMATION_TYPE_POPULARITY: while (--current_list_position >= 0) { otherRide = &g_ride_list[w->list_item_positions[current_list_position]]; - if ((ride->var_158 & 0xFF) * 4 <= (otherRide->var_158 & 0xFF) * 4) + if (ride->popularity * 4 <= otherRide->popularity * 4) break; window_bubble_list_item(w, current_list_position); @@ -625,7 +668,7 @@ static void window_ride_list_refresh_list(rct_window *w) case INFORMATION_TYPE_SATISFACTION: while (--current_list_position >= 0) { otherRide = &g_ride_list[w->list_item_positions[current_list_position]]; - if ((ride->var_14A & 0xFF) * 5 <= (otherRide->var_14A & 0xFF) * 5) + if (ride->satisfaction * 5 <= otherRide->satisfaction * 5) break; window_bubble_list_item(w, current_list_position); @@ -661,7 +704,7 @@ static void window_ride_list_refresh_list(rct_window *w) case INFORMATION_TYPE_RELIABILITY: while (--current_list_position >= 0) { otherRide = &g_ride_list[w->list_item_positions[current_list_position]]; - if (ride->var_196 >> 8 <= otherRide->var_196 >> 8) + if (ride->reliability >> 8 <= otherRide->reliability >> 8) break; window_bubble_list_item(w, current_list_position); @@ -670,7 +713,7 @@ static void window_ride_list_refresh_list(rct_window *w) case INFORMATION_TYPE_DOWN_TIME: while (--current_list_position >= 0) { otherRide = &g_ride_list[w->list_item_positions[current_list_position]]; - if (ride->var_199 <= otherRide->var_199) + if (ride->downtime <= otherRide->downtime) break; window_bubble_list_item(w, current_list_position); @@ -707,7 +750,7 @@ static void window_ride_list_close_all(rct_window *w) RCT2_GLOBAL(0x013CE952 + 6, uint16) = w->scrolls[0].v_top; RCT2_GLOBAL(0x013CE952 + 8, uint32) = w->scrolls[0].v_bottom; - game_do_command(0, 1, 0, i, GAME_COMMAND_SET_RIDE_OPEN, 0, 0); + ride_set_status(i, RIDE_STATUS_CLOSED); } } @@ -724,6 +767,6 @@ static void window_ride_list_open_all(rct_window *w) RCT2_GLOBAL(0x013CE952 + 6, uint16) = w->scrolls[0].v_top; RCT2_GLOBAL(0x013CE952 + 8, uint32) = w->scrolls[0].v_bottom; - game_do_command(0, 1, 0, (1 << 8) | i, GAME_COMMAND_SET_RIDE_OPEN, 0, 0); + ride_set_status(i, RIDE_STATUS_OPEN); } } diff --git a/src/windows/save_prompt.c b/src/windows/save_prompt.c index 2fb1a9cac1..61f5f40419 100644 --- a/src/windows/save_prompt.c +++ b/src/windows/save_prompt.c @@ -28,6 +28,7 @@ #include "../openrct2.h" #include "../sprites.h" #include "../tutorial.h" +#include "../interface/themes.h" enum WINDOW_SAVE_PROMPT_WIDGET_IDX { WIDX_BACKGROUND, @@ -70,6 +71,7 @@ static rct_widget window_quit_prompt_widgets[] = { static void window_save_prompt_emptysub() { } static void window_save_prompt_close(); static void window_save_prompt_mouseup(); +static void window_save_prompt_invalidate(); static void window_save_prompt_paint(); static void* window_save_prompt_events[] = { @@ -98,7 +100,7 @@ static void* window_save_prompt_events[] = { window_save_prompt_emptysub, window_save_prompt_emptysub, window_save_prompt_emptysub, - window_save_prompt_emptysub, + window_save_prompt_invalidate, window_save_prompt_paint, window_save_prompt_emptysub }; @@ -109,34 +111,62 @@ static void* window_save_prompt_events[] = { */ void window_save_prompt_open() { - int stringId, x, y; + int stringId, width, height; rct_window* window; unsigned short prompt_mode; rct_widget *widgets; uint64 enabled_widgets; prompt_mode = RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16); + if (prompt_mode == PM_QUIT) + prompt_mode = PM_SAVE_BEFORE_QUIT; // do not show save prompt if we're in the title demo and click on load game - if (prompt_mode != PM_QUIT && RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) { game_load_or_quit_no_save_prompt(); return; } + if (!gConfigGeneral.confirmation_prompt) { + /* game_load_or_quit_no_save_prompt() will exec requested task and close this window + * immediately again. + * TODO restructure these functions when we're sure game_load_or_quit_no_save_prompt() + * and game_load_or_quit() are not called by the original binary anymore. + */ + + if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 1) { + RCT2_CALLPROC_EBPSAFE(0x0066EE54); + game_load_or_quit_no_save_prompt(); + return; + } + else { + tutorial_stop(); + game_load_or_quit_no_save_prompt(); + return; + } + } + + if (RCT2_GLOBAL(0x009DEA66, uint16) < 3840) { + game_load_or_quit_no_save_prompt(); + return; + } + } + // Check if window is already open window = window_bring_to_front_by_class(WC_SAVE_PROMPT); if (window){ window_close(window); } - if (prompt_mode == PM_QUIT) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { widgets = window_quit_prompt_widgets; enabled_widgets = (1 << WQIDX_CLOSE) | (1 << WQIDX_OK) | (1 << WQIDX_CANCEL); - x = 177; - y = 34; + width = 177; + height = 34; } else { widgets = window_save_prompt_widgets; enabled_widgets = @@ -144,27 +174,24 @@ void window_save_prompt_open() (1 << WIDX_SAVE) | (1 << WIDX_DONT_SAVE) | (1 << WIDX_CANCEL); - x = 260; - y = 50; + width = 260; + height = 50; } - window = window_create( - (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2) - x / 2, - max(28, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) / 2) - y / 2), - x, - y, - (uint32*)window_save_prompt_events, - WC_SAVE_PROMPT, - WF_TRANSPARENT | WF_STICK_TO_FRONT - ); + window = window_create_centred( + width, + height, + (uint32*)window_save_prompt_events, + WC_SAVE_PROMPT, + WF_TRANSPARENT | WF_STICK_TO_FRONT + ); window->widgets = widgets; window->enabled_widgets = enabled_widgets; window_init_scroll_widgets(window); - window->colours[0] = 154; // Pause the game - RCT2_GLOBAL(0x009DEA6E, uint8) |= 2; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) |= 2; pause_sounds(); window_invalidate_by_class(WC_TOP_TOOLBAR); @@ -175,37 +202,6 @@ void window_save_prompt_open() stringId = STR_QUIT_SCENARIO_EDITOR; window_save_prompt_widgets[WIDX_TITLE].image = stringId; window_save_prompt_widgets[WIDX_LABEL].image = prompt_mode + STR_SAVE_BEFORE_LOADING; - - if (!gGeneral_config.confirmation_prompt) { - /* game_load_or_quit_no_save_prompt() will exec requested task and close this window - * immediately again. - * TODO restructure these functions when we're sure game_load_or_quit_no_save_prompt() - * and game_load_or_quit() are not called by the original binary anymore. - */ - - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 0x0D) { - game_load_or_quit_no_save_prompt(); - return; - } - - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) { - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 1) { - RCT2_CALLPROC_EBPSAFE(0x0066EE54); - game_load_or_quit_no_save_prompt(); - return; - } else { - tutorial_stop(); - game_load_or_quit_no_save_prompt(); - return; - } - } - - if (RCT2_GLOBAL(0x009DEA66, uint16) < 3840) { - game_load_or_quit_no_save_prompt(); - return; - } - } - } /** @@ -215,7 +211,7 @@ void window_save_prompt_open() static void window_save_prompt_close() { // Unpause the game - RCT2_GLOBAL(0x009DEA6E, uint8) &= ~2; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) &= ~2; unpause_sounds(); window_invalidate_by_class(WC_TOP_TOOLBAR); } @@ -228,16 +224,13 @@ static void window_save_prompt_mouseup() { short widgetIndex; rct_window *w; - short prompt_mode; window_widget_get_registers(w, widgetIndex); - prompt_mode = RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16); - - if (prompt_mode == PM_QUIT) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { switch (widgetIndex) { case WQIDX_OK: - openrct2_finish(); + game_load_or_quit_no_save_prompt(); break; case WQIDX_CLOSE: case WQIDX_CANCEL: @@ -263,12 +256,6 @@ static void window_save_prompt_mouseup() return; } } - - - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 0x0D) { - game_load_or_quit_no_save_prompt(); - return; - } if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) { if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 1) { @@ -288,6 +275,14 @@ static void window_save_prompt_mouseup() } } +static void window_save_prompt_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + static void window_save_prompt_paint() { rct_window *w; diff --git a/src/windows/scenery.c b/src/windows/scenery.c index 02ad9a6ac3..aa495fd77b 100644 --- a/src/windows/scenery.c +++ b/src/windows/scenery.c @@ -32,7 +32,12 @@ #include "../world/scenery.h" #include "../world/sprite.h" #include "dropdown.h" -#include "scenery.h" +#include "../interface/themes.h" + +#define WINDOW_SCENERY_WIDTH 634 +#define WINDOW_SCENERY_HEIGHT 142 +#define SCENERY_BUTTON_WIDTH 66 +#define SCENERY_BUTTON_HEIGHT 80 enum { WINDOW_SCENERY_TAB_1, @@ -55,7 +60,7 @@ enum { WINDOW_SCENERY_TAB_18, WINDOW_SCENERY_TAB_19, WINDOW_SCENERY_TAB_20 -} WINDOW_SCENERY_LIST_TAB; +}; static void window_scenery_emptysub() { } static void window_scenery_close(); @@ -174,12 +179,15 @@ static rct_widget window_scenery_widgets[] = { { WIDGETS_END }, }; -static sint16 window_scenery_tab_entries[0x13][SCENERY_ENTRIES_BY_TAB + 1]; +// rct2: 0x00F64F2C +sint16 window_scenery_tab_entries[20][SCENERY_ENTRIES_BY_TAB + 1]; -/* -* Was part of 0x006DFA00 -* The same code repeated five times for every scenery entry type -*/ +void window_scenery_update_scroll(rct_window *w); + +/** + * Was part of 0x006DFA00 + * The same code repeated five times for every scenery entry type + */ void init_scenery_entry(rct_scenery_entry *sceneryEntry, int index, uint8 sceneryTabId) { if (RCT2_ADDRESS(0x01357BD0, sint32)[index >> 5] & (1 << (index & 0x1F))) { if (sceneryTabId != 0xFF) { @@ -217,11 +225,13 @@ void init_scenery_entry(rct_scenery_entry *sceneryEntry, int index, uint8 scener } } -/* -* rct2: 0x006DFA00 -**/ -void init_scenery() { - bool enabledScenerySets[0x13] = { false }; +/** + * + * rct2: 0x006DFA00 + */ +void init_scenery() +{ + bool enabledScenerySets[0x14] = { false }; for (int scenerySetIndex = 0; scenerySetIndex < 0x14; scenerySetIndex++) { window_scenery_tab_entries[scenerySetIndex][0] = -1; @@ -344,7 +354,7 @@ void init_scenery() { uint32 tabIndex = tabIndexes[i]; rct_widget* tabWidget = &window_scenery_widgets[tabIndex + WIDX_SCENERY_TAB_1]; - if (left != 3 || tabIndex == 0x13) { + if (left != 3 || tabIndex != 0x13) { if (window_scenery_tab_entries[tabIndex][0] == -1) continue; @@ -366,9 +376,41 @@ void init_scenery() { window_invalidate_by_class(WC_SCENERY); } -/* -* rct2: 0x006E0FEF -**/ +/** + * + * rct2: 0x006DFEE4 + */ +void scenery_set_default_placement_configuration() +{ + window_scenery_rotation = 3; + window_scenery_primary_colour = 26; + window_scenery_secondary_colour = 18; + window_scenery_tertiary_colour = 24; + init_scenery(); + + for (int i = 0; i < 20; i++) + window_scenery_selected_scenery_by_tab[i] = -1; + + for (int i = 0; i < 20; i++) { + if (window_scenery_tab_entries[i][0] != -1) { + window_scenery_active_tab_index = i; + return; + } + } + + for (int i = 0; i < 16; i++) { + rct_widget *tabWidget = &window_scenery_widgets[WIDX_SCENERY_TAB_1 + i]; + if (tabWidget->type != WWT_EMPTY) { + window_scenery_active_tab_index = i; + return; + } + } +} + +/** + * + * rct2: 0x006E0FEF + */ void window_scenery_open() { rct_window* window; @@ -380,8 +422,15 @@ void window_scenery_open() init_scenery(); - window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - WINDOW_SCENERY_WIDTH, 0x1D, WINDOW_SCENERY_WIDTH, WINDOW_SCENERY_HEIGHT, - (uint32*)window_scenery_events, WC_SCENERY, WF_2); + window = window_create( + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - WINDOW_SCENERY_WIDTH, + 0x1D, + WINDOW_SCENERY_WIDTH, + WINDOW_SCENERY_HEIGHT, + (uint32*)window_scenery_events, + WC_SCENERY, + WF_2 + ); window->widgets = window_scenery_widgets; window->enabled_widgets = @@ -414,16 +463,16 @@ void window_scenery_open() (1 << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); window_init_scroll_widgets(window); - RCT2_CALLPROC_X(0x006E1EB4, 0, 0, 0, 0, (int)window, 0, 0); + window_scenery_update_scroll(window); show_gridlines(); window_scenery_rotation = 3; - RCT2_GLOBAL(0x00F64F12, uint8) = 0; - RCT2_GLOBAL(0x00F64F13, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) = 0; window->scenery.selected_scenery_id = -1; window->scenery.hover_counter = 0; window_push_others_below(window); RCT2_GLOBAL(0x00F64F0D, uint8) = 0; - RCT2_GLOBAL(0x00F64EB4, uint32) = 0x80000000; + RCT2_GLOBAL(0x00F64EB4, uint32) = MONEY32_UNDEFINED; RCT2_GLOBAL(0x00F64EC0, uint16) = 0; window_scenery_is_repaint_scenery_tool_on = 0; // repaint colored scenery tool state window_scenery_is_build_cluster_tool_on = 0; // build cluster tool state @@ -432,14 +481,12 @@ void window_scenery_open() window->max_width = WINDOW_SCENERY_WIDTH; window->min_height = WINDOW_SCENERY_HEIGHT; window->max_height = WINDOW_SCENERY_HEIGHT; - window->colours[0] = 0x18; - window->colours[1] = 0x0C; - window->colours[2] = 0x0C; } -/* - * rct2: 0x0066DB3D -*/ +/** + * + * rct2: 0x0066DB3D + */ bool window_scenery_is_scenery_tool_active() { int toolWindowClassification = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass); int toolWidgetIndex = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, rct_windownumber); @@ -452,23 +499,25 @@ bool window_scenery_is_scenery_tool_active() { } -/* -* rct2: 0x006E1A73 -**/ +/** + * + * rct2: 0x006E1A73 + */ void window_scenery_close() { rct_window *w; window_get_register(w); - RCT2_CALLPROC_EBPSAFE(0x006E2712); + scenery_remove_ghost_tool_placement(); hide_gridlines(); - RCT2_CALLPROC_X(0x006CB70A, 0, 0, 0, 0, 0, 0, 0); + viewport_set_visibility(0); if (window_scenery_is_scenery_tool_active()) tool_cancel(); } -int window_scenery_scrollgetsize_num() { +int window_scenery_scrollgetsize_num() +{ int items = 0; while (window_scenery_tab_entries[window_scenery_active_tab_index][items] != -1) items++; @@ -482,9 +531,9 @@ int window_scenery_scrollgetsize_num() { } /** -* -* rct2: 0x006BD94C -*/ + * + * rct2: 0x006BD94C + */ static void window_scenery_mouseup() { short widgetIndex; @@ -499,7 +548,7 @@ static void window_scenery_mouseup() case WIDX_SCENERY_ROTATE_OBJECTS_BUTTON: window_scenery_rotation++; window_scenery_rotation = window_scenery_rotation % 4; - RCT2_CALLPROC_EBPSAFE(0x006E2712); + scenery_remove_ghost_tool_placement(); window_invalidate(w); break; case WIDX_SCENERY_REPAINT_SCENERY_BUTTON: @@ -514,12 +563,12 @@ static void window_scenery_mouseup() } /* -* -* rct2: 0x006E1EB4 -*/ -void window_scenery_update_scroll(rct_window *w) { - int scrollsize = window_scenery_scrollgetsize_num(); - w->scrolls[0].v_bottom = scrollsize; + * + * rct2: 0x006E1EB4 + */ +void window_scenery_update_scroll(rct_window *w) +{ + w->scrolls[0].v_bottom = window_scenery_scrollgetsize_num() + 1; int tabIndex = window_scenery_active_tab_index; @@ -543,9 +592,9 @@ void window_scenery_update_scroll(rct_window *w) { } /** -* -* rct2: 0x006E1E48 -*/ + * + * rct2: 0x006E1E48 + */ static void window_scenery_resize() { rct_window *w; @@ -553,32 +602,40 @@ static void window_scenery_resize() window_get_register(w); if (w->width < w->min_width) { + window_invalidate(w); w->width = w->min_width; window_invalidate(w); } if (w->width > w->max_width) { + window_invalidate(w); w->width = w->max_width; window_invalidate(w); } if (w->height < w->min_height) { + window_invalidate(w); w->height = w->min_height; window_invalidate(w); + // HACK: For some reason invalidate has not been called + window_event_invalidate_call(w); window_scenery_update_scroll(w); } if (w->height > w->max_height) { + window_invalidate(w); w->height = w->max_height; window_invalidate(w); + // HACK: For some reason invalidate has not been called + window_event_invalidate_call(w); window_scenery_update_scroll(w); } } /** -* -* rct2: 0x006E1A25 -*/ + * + * rct2: 0x006E1A25 + */ static void window_scenery_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) { switch (widgetIndex) { case WIDX_SCENERY_PRIMARY_COLOUR_BUTTON: @@ -595,15 +652,15 @@ static void window_scenery_mousedown(int widgetIndex, rct_window* w, rct_widget* if (widgetIndex >= WIDX_SCENERY_TAB_1 && widgetIndex <= WIDX_SCENERY_TAB_20) { window_scenery_active_tab_index = widgetIndex - WIDX_SCENERY_TAB_1; window_invalidate(w); - RCT2_GLOBAL(0x00F64EB4, uint32) = 0x80000000; + RCT2_GLOBAL(0x00F64EB4, uint32) = MONEY32_UNDEFINED; window_scenery_update_scroll(w); } } /** -* -* rct2: 0x006E1A54 -*/ + * + * rct2: 0x006E1A54 + */ static void window_scenery_dropdown() { rct_window* w; short widgetIndex, dropdownIndex; @@ -626,9 +683,9 @@ static void window_scenery_dropdown() { } /** -* -* rct2: 0x006E1B9F -*/ + * + * rct2: 0x006E1B9F + */ static void window_scenery_event_07() { rct_window *w; @@ -640,21 +697,19 @@ static void window_scenery_event_07() { } /** -* -* rct2: 0x006E1CD3 -*/ + * + * rct2: 0x006E1CD3 + */ static void window_scenery_update(rct_window *w) { - rct_window* other = window_find_from_point(RCT2_GLOBAL(0x0142406C, int), RCT2_GLOBAL(0x01424070, int)); + rct_window *other = window_find_from_point(RCT2_GLOBAL(0x0142406C, int), RCT2_GLOBAL(0x01424070, int)); if (other == w) { - int window_x = RCT2_GLOBAL(0x0142406C, int) - w->x + 0x1A; + int window_x = RCT2_GLOBAL(0x0142406C, int) - w->x + 26; int window_y = RCT2_GLOBAL(0x01424070, int) - w->y; - if (window_y < 0x2C || window_x <= w->width) { - int widgetIndex = window_find_widget_from_point(w, - RCT2_GLOBAL(0x0142406C, int), RCT2_GLOBAL(0x01424070, int)); - - if (widgetIndex >= 3) { + if (window_y < 44 || window_x <= w->width) { + int widgetIndex = window_find_widget_from_point(w, RCT2_GLOBAL(0x0142406C, int), RCT2_GLOBAL(0x01424070, int)); + if (widgetIndex >= WIDX_SCENERY_TAB_CONTENT_PANEL) { w->scenery.hover_counter++; if (w->scenery.hover_counter < 8) { if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) != INPUT_STATE_SCROLL_LEFT) { @@ -664,13 +719,9 @@ static void window_scenery_update(rct_window *w) w->max_height = WINDOW_SCENERY_HEIGHT; } } else { - int windowHeight = w->scrolls[0].v_bottom + 0x3E; - if (windowHeight > 0x1C6) - windowHeight = 0x1C6; - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) < 0x258){ - if (windowHeight > 0x176) - windowHeight = 0x176; - } + int windowHeight = min(454, w->scrolls[0].v_bottom - 1 + 62); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) < 600) + windowHeight = min(374, windowHeight); w->min_width = WINDOW_SCENERY_WIDTH; w->max_width = WINDOW_SCENERY_WIDTH; @@ -689,11 +740,13 @@ static void window_scenery_update(rct_window *w) } } - gfx_invalidate_screen(); + window_invalidate(w); - if (!window_scenery_is_scenery_tool_active()) + if (!window_scenery_is_scenery_tool_active()){ window_close(w); - + return; + } + if (window_scenery_is_repaint_scenery_tool_on == 1) { // the repaint scenery tool is active RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 0x17; } else { @@ -721,20 +774,21 @@ static void window_scenery_update(rct_window *w) } /** -* -* rct2: 0x006E1A91 -*/ -void window_scenery_scrollgetsize() { - int scrollHeight = window_scenery_scrollgetsize_num(); + * + * rct2: 0x006E1A91 + */ +void window_scenery_scrollgetsize() +{ + int width, height; -#ifdef _MSC_VER - __asm mov edx, scrollHeight -#else - __asm__("mov edx, %[scrollHeight] " : [scrollHeight] "+m" (scrollHeight)); -#endif + width = 0; + height = window_scenery_scrollgetsize_num(); + + window_scrollsize_set_registers(width, height); } -short get_scenery_id_by_cursor_pos(short x, short y) { +short get_scenery_id_by_cursor_pos(short x, short y) +{ int tabSceneryIndex = x / SCENERY_BUTTON_WIDTH + (y / SCENERY_BUTTON_HEIGHT) * 9; uint8 tabIndex = window_scenery_active_tab_index; @@ -752,14 +806,15 @@ short get_scenery_id_by_cursor_pos(short x, short y) { } /** -* -* rct2: 0x006E1C4A -*/ -void window_scenery_scrollmousedown() { - short x, y; + * + * rct2: 0x006E1C4A + */ +void window_scenery_scrollmousedown() +{ + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); short sceneryId = get_scenery_id_by_cursor_pos(x, y); if (sceneryId == -1) @@ -771,19 +826,20 @@ void window_scenery_scrollmousedown() { window_scenery_is_repaint_scenery_tool_on &= 0xFE; sound_play_panned(4, (w->width >> 1) + w->x, 0, 0, 0); w->scenery.hover_counter = -16; - RCT2_GLOBAL(0x00F64EB4, uint32) = 0x80000000; + RCT2_GLOBAL(0x00F64EB4, uint32) = MONEY32_UNDEFINED; window_invalidate(w); } /** -* -* rct2: 0x006E1BB8 -*/ -void window_scenery_scrollmouseover() { - short x, y; + * + * rct2: 0x006E1BB8 + */ +void window_scenery_scrollmouseover() +{ + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); short sceneryId = get_scenery_id_by_cursor_pos(x, y); if (sceneryId != -1) { w->scenery.selected_scenery_id = sceneryId; @@ -792,53 +848,70 @@ void window_scenery_scrollmouseover() { } /** -* -* rct2: 0x006E1C05 -*/ -void window_scenery_tooltip() { - uint16 tooltipIndex; + * + * rct2: 0x006E1C05 + */ +void window_scenery_tooltip() +{ + rct_window *w; + short widget; - #ifdef _MSC_VER - __asm mov tooltipIndex, ax - #else - __asm__("mov %[tooltipIndex], ax " : [tooltipIndex] "+m" (tooltipIndex)); - #endif + window_scroll_get_registers(w, widget); - if (tooltipIndex == 0x18) - { + switch (widget) { + case WIDX_SCENERY_LIST: RCT2_GLOBAL(0x013CE952, uint16) = 3159; - } - else if (tooltipIndex >= 4 && tooltipIndex < 0x17) - { - RCT2_GLOBAL(0x013CE952, uint16) = g_scenerySetEntries[tooltipIndex - 4]->name; + break; + case WIDX_SCENERY_TAB_1: + case WIDX_SCENERY_TAB_2: + case WIDX_SCENERY_TAB_3: + case WIDX_SCENERY_TAB_4: + case WIDX_SCENERY_TAB_5: + case WIDX_SCENERY_TAB_6: + case WIDX_SCENERY_TAB_7: + case WIDX_SCENERY_TAB_8: + case WIDX_SCENERY_TAB_9: + case WIDX_SCENERY_TAB_10: + case WIDX_SCENERY_TAB_11: + case WIDX_SCENERY_TAB_12: + case WIDX_SCENERY_TAB_13: + case WIDX_SCENERY_TAB_14: + case WIDX_SCENERY_TAB_15: + case WIDX_SCENERY_TAB_16: + case WIDX_SCENERY_TAB_17: + case WIDX_SCENERY_TAB_18: + case WIDX_SCENERY_TAB_19: + case WIDX_SCENERY_TAB_20: + RCT2_GLOBAL(0x013CE952, uint16) = g_scenerySetEntries[widget - WIDX_SCENERY_TAB_1]->name; + break; } } /** -* -* rct2: 0x006E118B -*/ -void window_scenery_invalidate() { + * + * rct2: 0x006E118B + */ +void window_scenery_invalidate() +{ rct_window* w; window_get_register(w); + colour_scheme_update(w); uint16 tabIndex = window_scenery_active_tab_index; - uint32 titleStringId = 0x715; - if (tabIndex <= 0x13) { + uint32 titleStringId = 1813; + if (tabIndex < 19) titleStringId = g_scenerySetEntries[tabIndex]->name; - } + window_scenery_widgets[WIDX_SCENERY_TITLE].image = titleStringId; w->pressed_widgets = (((uint32)w->pressed_widgets & 0xFF00000F) | (1 << (tabIndex + 4))) & 0xBBFFFFFF; - if (window_scenery_is_repaint_scenery_tool_on == 1) { + if (window_scenery_is_repaint_scenery_tool_on == 1) w->pressed_widgets |= (1 << WIDX_SCENERY_REPAINT_SCENERY_BUTTON); - } - if (window_scenery_is_build_cluster_tool_on == 1) { + if (window_scenery_is_build_cluster_tool_on == 1) w->pressed_widgets |= (1 << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); - } window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WWT_EMPTY; window_scenery_widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WWT_EMPTY; @@ -854,7 +927,7 @@ void window_scenery_invalidate() { window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WWT_FLATBTN; } } - else if (tabSelectedSceneryId > 0x300) { + else if (tabSelectedSceneryId >= 0x300) { window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WWT_FLATBTN; } } @@ -875,8 +948,7 @@ void window_scenery_invalidate() { window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WWT_COLORBTN; window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WWT_COLORBTN; window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WWT_EMPTY; - } - else if (tabSelectedSceneryId != -1) { + } else if (tabSelectedSceneryId != -1) { rct_scenery_entry* sceneryEntry = NULL; if (tabSelectedSceneryId >= 0x400) { @@ -884,16 +956,14 @@ void window_scenery_invalidate() { if (sceneryEntry->banner.flags & 1) window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLORBTN; - } - else if (tabSelectedSceneryId >= 0x300) { + } else if (tabSelectedSceneryId >= 0x300) { sceneryEntry = g_largeSceneryEntries[tabSelectedSceneryId - 0x300]; if (sceneryEntry->large_scenery.flags & 1) window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLORBTN; if (sceneryEntry->large_scenery.flags & 2) window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WWT_COLORBTN; - } - else if (tabSelectedSceneryId >= 0x200) { + } else if (tabSelectedSceneryId >= 0x200) { sceneryEntry = g_wallSceneryEntries[tabSelectedSceneryId - 0x200]; if (sceneryEntry->wall.flags & (WALL_SCENERY_FLAG1 | WALL_SCENERY_FLAG2)) { window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLORBTN; @@ -907,14 +977,13 @@ void window_scenery_invalidate() { window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WWT_COLORBTN; } } - } - else if (tabSelectedSceneryId < 0x100) { + } else if (tabSelectedSceneryId < 0x100) { sceneryEntry = g_smallSceneryEntries[tabSelectedSceneryId]; - if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG10)) { + if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG10)) { window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLORBTN; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_HAS_SECONDARY_COLOUR) + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WWT_COLORBTN; } } @@ -927,8 +996,8 @@ void window_scenery_invalidate() { window_scenery_widgets[WIDX_SCENERY_TITLE].right = w->width - 2; window_scenery_widgets[WIDX_SCENERY_CLOSE].left = w->width - 13; window_scenery_widgets[WIDX_SCENERY_CLOSE].right = window_scenery_widgets[WIDX_SCENERY_CLOSE].left + 10; - window_scenery_widgets[WIDX_SCENERY_LIST].right = w->width - 0x1A; - window_scenery_widgets[WIDX_SCENERY_LIST].bottom = w->height - 0x0E; + window_scenery_widgets[WIDX_SCENERY_LIST].right = w->width - 26; + window_scenery_widgets[WIDX_SCENERY_LIST].bottom = w->height - 14; window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].left = w->width - 25; window_scenery_widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].left = w->width - 25; @@ -946,10 +1015,11 @@ void window_scenery_invalidate() { } /** -* -* rct2: 0x006E1462 -*/ -void window_scenery_paint() { + * + * rct2: 0x006E1462 + */ +void window_scenery_paint() +{ rct_window *w; rct_drawpixelinfo *dpi; @@ -997,7 +1067,7 @@ void window_scenery_paint() { price = sceneryEntry->small_scenery.price * 10; } - if (w->scenery.selected_scenery_id == -1 && RCT2_GLOBAL(0x00F64EB4, uint32) != 0x80000000) { + if (w->scenery.selected_scenery_id == -1 && RCT2_GLOBAL(0x00F64EB4, uint32) != MONEY32_UNDEFINED) { price = RCT2_GLOBAL(0x00F64EB4, uint32); } @@ -1061,16 +1131,14 @@ void window_scenery_scrollpaint() gfx_draw_sprite(dpi, imageId, left + 0x21, top + 0x28, w->colours[1]); gfx_draw_sprite(dpi, imageId + 1, left + 0x21, top + 0x28, w->colours[1]); - } - else if (currentSceneryGlobalId >= 0x300) { + } else if (currentSceneryGlobalId >= 0x300) { sceneryEntry = g_largeSceneryEntries[currentSceneryGlobalId - 0x300]; uint32 imageId = sceneryEntry->image + window_scenery_rotation; imageId |= (window_scenery_primary_colour << 19) | 0x20000000; imageId |= (window_scenery_secondary_colour << 24) | 0x80000000; gfx_draw_sprite(dpi, imageId, left + 0x21, top, w->colours[1]); - } - else if (currentSceneryGlobalId >= 0x200) { + } else if (currentSceneryGlobalId >= 0x200) { sceneryEntry = g_wallSceneryEntries[currentSceneryGlobalId - 0x200]; rct_drawpixelinfo* clipdpi = clip_drawpixelinfo(dpi, left + 1, 64, top + 1, 78); if (clipdpi != NULL) { @@ -1086,7 +1154,7 @@ void window_scenery_scrollpaint() gfx_draw_sprite(clipdpi, imageId, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, tertiaryColour); - imageId = (sceneryEntry->image + 0x40000006) | (window_scenery_primary_colour << 19); + imageId = (sceneryEntry->image + 0x40000006) | ((window_scenery_primary_colour + 0x70) << 19); gfx_draw_sprite(clipdpi, imageId, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, tertiaryColour); } @@ -1114,8 +1182,7 @@ void window_scenery_scrollpaint() rct2_free(clipdpi); } - } - else if (currentSceneryGlobalId >= 0x100) { + } else if (currentSceneryGlobalId >= 0x100) { sceneryEntry = g_pathBitSceneryEntries[currentSceneryGlobalId - 0x100]; uint32 imageId = sceneryEntry->image; @@ -1127,18 +1194,18 @@ void window_scenery_scrollpaint() uint32 imageId = sceneryEntry->image + window_scenery_rotation; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_HAS_PRIMARY_COLOUR) { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR) { imageId |= (window_scenery_primary_colour << 19) | 0x20000000; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_HAS_SECONDARY_COLOUR) { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) { imageId |= (window_scenery_secondary_colour << 24) | 0x80000000; } } uint16 spriteTop = (sceneryEntry->small_scenery.height / 4) + 0x2B; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG1 && - sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG2) { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE && + sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE) { spriteTop -= 0x0C; } diff --git a/src/windows/shortcut_key_change.c b/src/windows/shortcut_key_change.c index 19558c3c05..01cf458ca6 100644 --- a/src/windows/shortcut_key_change.c +++ b/src/windows/shortcut_key_change.c @@ -23,6 +23,7 @@ #include "../interface/window.h" #include "../interface/widget.h" #include "../localisation/localisation.h" +#include "../interface/themes.h" #define WW 250 #define WH 60 @@ -43,6 +44,7 @@ static rct_widget window_shortcut_change_widgets[] = { static void window_shortcut_change_emptysub(){} static void window_shortcut_change_mouseup(); +static void window_shortcut_change_invalidate(); static void window_shortcut_change_paint(); //0x9A3F7C @@ -72,7 +74,7 @@ static void* window_shortcut_change_events[] = { window_shortcut_change_emptysub, window_shortcut_change_emptysub, window_shortcut_change_emptysub, - window_shortcut_change_emptysub, + window_shortcut_change_invalidate, window_shortcut_change_paint, window_shortcut_change_emptysub }; @@ -87,9 +89,6 @@ void window_shortcut_change_open(int selected_key){ w->widgets = window_shortcut_change_widgets; w->enabled_widgets = (1 << 2); window_init_scroll_widgets(w); - w->colours[0] = 7; - w->colours[1] = 7; - w->colours[2] = 7; } /** @@ -108,6 +107,14 @@ static void window_shortcut_change_mouseup(){ } } +static void window_shortcut_change_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + /** * * rct2: 0x006E3A9F diff --git a/src/windows/shortcut_keys.c b/src/windows/shortcut_keys.c index 4d86e965c6..24e6db0dd9 100644 --- a/src/windows/shortcut_keys.c +++ b/src/windows/shortcut_keys.c @@ -23,7 +23,8 @@ #include "../interface/window.h" #include "../interface/widget.h" #include "../localisation/localisation.h" -#include "../platform/osinterface.h" +#include "../platform/platform.h" +#include "../interface/themes.h" #define WW 340 #define WH 240 @@ -48,6 +49,7 @@ static rct_widget window_shortcut_widgets[] = { void window_shortcut_emptysub() { } static void window_shortcut_mouseup(); +static void window_shortcut_invalidate(); static void window_shortcut_paint(); static void window_shortcut_tooltip(); static void window_shortcut_scrollgetsize(); @@ -81,7 +83,7 @@ static void* window_shortcut_events[] = { window_shortcut_tooltip, window_shortcut_emptysub, window_shortcut_emptysub, - window_shortcut_emptysub, + window_shortcut_invalidate, window_shortcut_paint, window_shortcut_scrollpaint }; @@ -104,9 +106,6 @@ void window_shortcut_keys_open() w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_RESET); window_init_scroll_widgets(w); - w->colours[0] = 7; - w->colours[1] = 7; - w->colours[2] = 7; w->no_list_items = 32; w->selected_list_item = -1; } @@ -128,12 +127,20 @@ static void window_shortcut_mouseup() break; case WIDX_RESET: config_reset_shortcut_keys(); - config_save(); + config_shortcut_keys_save(); window_invalidate(w); break; } } +static void window_shortcut_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + /** * * rct2: 0x006E38E0 @@ -163,17 +170,15 @@ static void window_shortcut_tooltip() */ static void window_shortcut_scrollgetsize() { - int y; rct_window *w; + int width, height; + window_get_register(w); - y = 32 * 10; + width = 0; + height = 32 * 10; -#ifdef _MSC_VER - __asm mov edx, y -#else - __asm__("mov edx, %[y] " : [y] "+m" (y)); -#endif + window_scrollsize_set_registers(width, height); } /** @@ -182,14 +187,14 @@ static void window_shortcut_scrollgetsize() */ static void window_shortcut_scrollmousedown() { - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); int selected_item = y / 10; - - if (selected_item >= w->no_list_items)return; + if (selected_item >= w->no_list_items) + return; window_shortcut_change_open(selected_item); } @@ -200,14 +205,14 @@ static void window_shortcut_scrollmousedown() */ static void window_shortcut_scrollmouseover() { - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); int selected_item = y / 10; - - if (selected_item >= w->no_list_items)return; + if (selected_item >= w->no_list_items) + return; w->selected_list_item = selected_item; @@ -227,14 +232,14 @@ static void window_shortcut_scrollpaint() gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, RCT2_ADDRESS(0x0141FC48,uint8)[w->colours[1] * 8]); - for (int i = 0; i < w->no_list_items; ++i){ + for (int i = 0; i < w->no_list_items; ++i) { int y = i * 10; - if (y > dpi->y + dpi->height) { + if (y > dpi->y + dpi->height) break; - } + if (y + 10 < dpi->y)continue; int format = STR_BLACK_STRING; - if (i == w->selected_list_item){ + if (i == w->selected_list_item) { format = STR_WINDOW_COLOUR_2_STRING; gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031); } @@ -243,33 +248,23 @@ static void window_shortcut_scrollpaint() RCT2_GLOBAL(0x13CE956, uint16) = 0; RCT2_GLOBAL(0x13CE958, uint16) = 0; - // This is the original version that will not take into account remapped keys. - //shortcut_entry sc_entry = RCT2_ADDRESS(RCT2_ADDRESS_CONFIG_KEYBOARD_SHORTCUTS, shortcut_entry)[i]; - //if (sc_entry.key != 255){ - // RCT2_GLOBAL(0x13CE958, uint16) = sc_entry.key + 2525; - // if (sc_entry.modifier){ - // RCT2_GLOBAL(0x13CE956, uint16) = 2782; - // if (sc_entry.key != 1){ - // RCT2_GLOBAL(0x13CE956, uint16) = 2783; - // } - // } - //} - uint16 shortcut_entry = gShortcutKeys[i]; - if (shortcut_entry != 0xFFFF){ - RCT2_GLOBAL(0x13CE958, uint16) = STR_INDIVIDUAL_KEYS_BASE + osinterface_scancode_to_rct_keycode(shortcut_entry & 0xFF); - //Display the modifer - if (shortcut_entry & 0x100){ + if (shortcut_entry != 0xFFFF) { + rct_string_id templateStringId = 2525; + const char *scanCodeName = SDL_GetScancodeName(shortcut_entry & 0xFF); + char *templateString = (char*)language_get_string(templateStringId); + strcpy(templateString, scanCodeName); + + RCT2_GLOBAL(0x13CE958, uint16) = templateStringId; + + // Display the modifer + if (shortcut_entry & 0x100) RCT2_GLOBAL(0x13CE956, uint16) = STR_SHIFT_PLUS; - } - else if (shortcut_entry & 0x200){ + else if (shortcut_entry & 0x200) RCT2_GLOBAL(0x13CE956, uint16) = STR_CTRL_PLUS; - } } - RCT2_GLOBAL(0x13CE952, uint16) = STR_SHORTCUT_ENTRY_FORMAT; - gfx_draw_string_left(dpi, format, (void*)0x13CE952, 0, 0, y - 1); } } \ No newline at end of file diff --git a/src/windows/sign.c b/src/windows/sign.c index aafae6f398..934638a368 100644 --- a/src/windows/sign.c +++ b/src/windows/sign.c @@ -32,6 +32,7 @@ #include "error.h" #include "dropdown.h" #include "../drawing/drawing.h" +#include "../interface/themes.h" #define WW 113 #define WH 96 @@ -152,7 +153,7 @@ void window_sign_open(rct_windownumber number) if (w != NULL) return; - w = window_create_auto_pos(WW, WH, (uint32*)window_sign_events, WC_BANNER, 0); + w = window_create_auto_pos(WW, WH, (uint32*)window_sign_events, WC_BANNER, WF_2); w->widgets = window_sign_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -163,21 +164,15 @@ void window_sign_open(rct_windownumber number) w->number = number; window_init_scroll_widgets(w); - w->colours[0] = 24; - w->colours[1] = 24; - w->colours[2] = 24; int view_x = gBanners[w->number].x << 5; int view_y = gBanners[w->number].y << 5; - int ebp = ((view_y << 8) | view_x) >> 5; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(ebp); + rct_map_element* map_element = map_get_first_element_at(view_x / 32, view_y / 32); while (1){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE){ - int ebx = map_element->properties.scenerymultiple.type; - ebx |= (map_element->properties.scenerymultiple.index & 0x3) << 8; - rct_scenery_entry* scenery_entry = g_largeSceneryEntries[ebx]; + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { + rct_scenery_entry* scenery_entry = g_largeSceneryEntries[map_element->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK]; if (scenery_entry->large_scenery.var_11 != 0xFF){ int id = (map_element->type & 0xC0) | ((map_element->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | @@ -213,10 +208,9 @@ void window_sign_open(rct_windownumber number) view_z, 0, -1 - ); + ); w->viewport->flags = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES) ? VIEWPORT_FLAG_GRIDLINES : 0; - w->flags |= WF_2; window_invalidate(w); } @@ -234,7 +228,7 @@ static void window_sign_mouseup() rct_string_id string_id; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(((y << 8) | x) >> 5); + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); switch (widgetIndex) { case WIDX_CLOSE: @@ -242,10 +236,8 @@ static void window_sign_mouseup() break; case WIDX_SIGN_DEMOLISH: while (1){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE){ - int ebx = map_element->properties.scenerymultiple.type; - ebx |= (map_element->properties.scenerymultiple.index & 0x3) << 8; - rct_scenery_entry* scenery_entry = g_largeSceneryEntries[ebx]; + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { + rct_scenery_entry* scenery_entry = g_largeSceneryEntries[map_element->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK]; if (scenery_entry->large_scenery.var_11 != 0xFF){ int id = (map_element->type & 0xC0) | ((map_element->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | @@ -260,8 +252,8 @@ static void window_sign_mouseup() x, 1 | ((map_element->type&0x3) << 8), y, - map_element->base_height | ((map_element->properties.scenerymultiple.index >> 2) << 8), - GAME_COMMAND_44, + map_element->base_height | ((map_element->properties.scenerymultiple.type >> 10) << 8), + GAME_COMMAND_REMOVE_LARGE_SCENERY, 0, 0); break; @@ -275,7 +267,7 @@ static void window_sign_mouseup() { string_id = gBanners[w->number].string_idx; } - window_text_input_open(w, WIDX_SIGN_TEXT, 2992, 2993, string_id, 0); + window_text_input_open(w, WIDX_SIGN_TEXT, 2992, 2993, string_id, 0, 32); break; } } @@ -320,13 +312,11 @@ static void window_sign_dropdown() int x = banner->x << 5; int y = banner->y << 5; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(((y << 8) | x) >> 5); + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); while (1){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE){ - int ebx = map_element->properties.scenerymultiple.type; - ebx |= (map_element->properties.scenerymultiple.index & 0x3) << 8; - rct_scenery_entry* scenery_entry = g_largeSceneryEntries[ebx]; + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { + rct_scenery_entry* scenery_entry = g_largeSceneryEntries[map_element->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK]; if (scenery_entry->large_scenery.var_11 != 0xFF){ int id = (map_element->type & 0xC0) | ((map_element->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | @@ -338,7 +328,7 @@ static void window_sign_dropdown() map_element++; } - int edx = map_element->base_height | ((map_element->properties.scenerymultiple.index >> 2) << 8); + int edx = map_element->base_height | ((map_element->properties.scenerymultiple.type >> 10) << 8); int ebp = w->list_information_type | (w->var_492 << 8); int ebx = (map_element->type & 0x3) << 8; RCT2_CALLPROC_X(0x6B9B05, x, ebx, y, edx, 0, w->number, ebp); @@ -361,17 +351,15 @@ static void window_sign_textinput() if (widgetIndex == WIDX_SIGN_TEXT && result) { if (*text != 0){ - int string_id = 0, ebx = 0, ecx = 128, edx = 0, ebp = 0, esi = 0; - RCT2_CALLFUNC_X(0x6C421D, &string_id, &ebx, &ecx, &edx, &esi, (int*)&text, &ebp); - if (string_id){ + rct_string_id string_id = user_string_allocate(128, text); + if (string_id != 0) { rct_string_id prev_string_id = banner->string_idx; banner->string_idx = string_id; user_string_free(prev_string_id); banner->flags &= ~(BANNER_FLAG_2); gfx_invalidate_screen(); - } - else{ + } else { window_error_open(2984, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); } } @@ -396,6 +384,7 @@ static void window_sign_invalidate() rct_window* w; window_get_register(w); + colour_scheme_update(w); rct_widget* main_colour_btn = &window_sign_widgets[WIDX_MAIN_COLOR]; rct_widget* text_colour_btn = &window_sign_widgets[WIDX_TEXT_COLOR]; @@ -499,13 +488,12 @@ void window_sign_small_open(rct_windownumber number){ int view_x = gBanners[w->number].x << 5; int view_y = gBanners[w->number].y << 5; - int ebp = ((view_y << 8) | view_x) >> 5; - - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(ebp); + + rct_map_element* map_element = map_get_first_element_at(view_x / 32, view_y / 32); while (1){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_FENCE){ - rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.slope]; + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_FENCE) { + rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.type]; if (scenery_entry->wall.var_0D != 0xFF){ if (map_element->properties.fence.item[0] == w->number) break; @@ -519,7 +507,7 @@ void window_sign_small_open(rct_windownumber number){ w->list_information_type = map_element->properties.fence.item[1] & 0x1F; w->var_492 = (map_element->properties.fence.item[1] >> 5) | ((map_element->flags&0x60) >> 2); - w->var_48C = map_element->properties.fence.slope; + w->var_48C = map_element->properties.fence.type; view_x += 16; view_y += 16; @@ -538,7 +526,7 @@ void window_sign_small_open(rct_windownumber number){ view_z, 0, -1 - ); + ); w->viewport->flags = (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES) ? VIEWPORT_FLAG_GRIDLINES : 0; w->flags |= WF_2; @@ -559,7 +547,7 @@ static void window_sign_small_mouseup() rct_string_id string_id; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(((y << 8) | x) >> 5); + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); switch (widgetIndex) { case WIDX_CLOSE: @@ -567,8 +555,8 @@ static void window_sign_small_mouseup() break; case WIDX_SIGN_DEMOLISH: while (1){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_FENCE){ - rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.slope]; + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_FENCE) { + rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.type]; if (scenery_entry->wall.var_0D != 0xFF){ if (map_element->properties.fence.item[0] == w->number) break; @@ -596,7 +584,7 @@ static void window_sign_small_mouseup() { string_id = gBanners[w->number].string_idx; } - window_text_input_open(w, WIDX_SIGN_TEXT, 2992, 2993, string_id, 0); + window_text_input_open(w, WIDX_SIGN_TEXT, 2992, 2993, string_id, 0, 32); break; } } @@ -626,11 +614,11 @@ static void window_sign_small_dropdown() int x = banner->x << 5; int y = banner->y << 5; - rct_map_element* map_element = TILE_MAP_ELEMENT_POINTER(((y << 8) | x) >> 5); + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); while (1){ - if ((map_element->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_FENCE){ - rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.slope]; + if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_FENCE) { + rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.type]; if (scenery_entry->wall.var_0D != 0xFF){ if (map_element->properties.fence.item[0] == w->number) break; @@ -645,7 +633,7 @@ static void window_sign_small_dropdown() ((w->var_492 & 0x7) << 5); map_element->flags |= ((w->var_492 & 0x18) << 2); - RCT2_CALLPROC_X(0x6EC847, x, 0, y, 0, map_element->clearance_height << 3, map_element->base_height << 3, 0); + gfx_invalidate_viewport_tile(x, y, map_element->base_height * 8, map_element->clearance_height * 8); window_invalidate(w); } @@ -655,6 +643,7 @@ static void window_sign_small_invalidate() rct_window* w; window_get_register(w); + colour_scheme_update(w); rct_widget* main_colour_btn = &window_sign_widgets[WIDX_MAIN_COLOR]; rct_widget* text_colour_btn = &window_sign_widgets[WIDX_TEXT_COLOR]; diff --git a/src/windows/staff.c b/src/windows/staff.c index 4848a6bee3..117d41d9ee 100644 --- a/src/windows/staff.c +++ b/src/windows/staff.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../interface/viewport.h" #include "../interface/widget.h" @@ -27,10 +28,13 @@ #include "../peep/peep.h" #include "../peep/staff.h" #include "../sprites.h" +#include "../world/footpath.h" #include "../world/sprite.h" #include "../world/scenery.h" +#include "../input.h" #include "dropdown.h" #include "error.h" +#include "../interface/themes.h" #define WW 190 #define WH 180 @@ -160,6 +164,8 @@ void window_staff_stats_invalidate(); void window_staff_stats_paint(); void window_staff_stats_tab_paint(rct_window* w, rct_drawpixelinfo* dpi); +void window_staff_set_colours(); + // 0x992AEC static void* window_staff_overview_events[] = { window_staff_overview_close, @@ -297,7 +303,7 @@ void window_staff_open(rct_peep* peep) { rct_window* w = window_bring_to_front_by_number(WC_PEEP, peep->sprite_index); if (w == NULL) { - w = window_create_auto_pos(WW, WH, (uint32*)window_staff_overview_events, WC_PEEP, (uint16)0x400); + w = window_create_auto_pos(WW, WH, (uint32*)window_staff_overview_events, WC_PEEP, WF_10 | WF_RESIZABLE); w->widgets = RCT2_GLOBAL(0x9AF81C, rct_widget*); w->enabled_widgets = RCT2_GLOBAL(0x9929B0, uint32); @@ -315,26 +321,20 @@ void window_staff_open(rct_peep* peep) w->max_width = 500; w->max_height = 450; - w->flags = 1 << 8; - - w->colours[0] = 1; - w->colours[1] = 4; - w->colours[2] = 4; } w->page = 0; window_invalidate(w); w->widgets = window_staff_overview_widgets; w->enabled_widgets = window_staff_page_enabled_widgets[0]; - w->var_020 = RCT2_GLOBAL(0x9929BC, uint32); + w->hold_down_widgets = 0; w->event_handlers = window_staff_page_events[0]; w->pressed_widgets = 0; window_staff_disable_widgets(w); window_init_scroll_widgets(w); window_staff_viewport_init(w); - if (g_sprite_list[w->number].peep.state == PEEP_STATE_PICKED) { - RCT2_CALLPROC_X(w->event_handlers[WE_MOUSE_UP], 0, 0, 0, 10, (int)w, 0, 0); - } + if (g_sprite_list[w->number].peep.state == PEEP_STATE_PICKED) + window_event_mouse_up_call(w, WIDX_CHECKBOX_3); } /** @@ -375,7 +375,7 @@ void window_staff_overview_close() window_get_register(w); - if (RCT2_GLOBAL(0x9DE518, uint32) & (1 << 3)){ + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE){ if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)) tool_cancel(); @@ -388,7 +388,7 @@ void window_staff_overview_close() */ void window_staff_set_page(rct_window* w, int page) { - if (RCT2_GLOBAL(0x9DE518,uint32) & (1 << 3)) + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) @@ -413,7 +413,7 @@ void window_staff_set_page(rct_window* w, int page) } w->enabled_widgets = window_staff_page_enabled_widgets[page]; - w->var_020 = RCT2_ADDRESS(0x9929BC, uint32)[page]; + w->hold_down_widgets = 0; w->event_handlers = window_staff_page_events[page]; w->pressed_widgets = 0; w->widgets = window_staff_page_widgets[page]; @@ -421,8 +421,8 @@ void window_staff_set_page(rct_window* w, int page) window_staff_disable_widgets(w); window_invalidate(w); - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); + window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); @@ -457,7 +457,7 @@ void window_staff_overview_mouseup() w->var_48C = peep->x; - RCT2_CALLPROC_X(0x0069A512, 0, 0, 0, 0, (int)peep, 0, 0); + remove_peep_from_ride(peep); invalidate_sprite((rct_sprite*)peep); sprite_move( 0x8000, peep->y, peep->z, (rct_sprite*)peep); @@ -469,7 +469,7 @@ void window_staff_overview_mouseup() window_staff_fire_prompt_open(peep); break; case WIDX_RENAME: - window_text_input_open(w, widgetIndex, 2977, 2978, peep->name_string_idx, peep->id); + window_text_input_open(w, widgetIndex, 2977, 2978, peep->name_string_idx, peep->id, 32); break; } } @@ -573,19 +573,18 @@ void window_staff_overview_dropdown() for (int i = 0; i < 128; i++) { - RCT2_GLOBAL(0x13B0E72 + ebx + i * 4, uint32) = 0; + RCT2_ADDRESS(0x13B0E72 + (peep->staff_id * 512), uint32)[i] = 0; } - RCT2_GLOBAL(RCT2_ADDRESS_STAFF_MODE_ARRAY + edi, uint16) &= 0xFD; // bug?? + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] &= ~2; - window_invalidate(w); - //RCT2_CALLPROC_EBPSAFE(0x006C0C3F); - sub_6C0C3F(); + gfx_invalidate_screen(); + staff_update_greyed_patrol_areas(); } else { if (!tool_set(w, widgetIndex, 22)) { show_gridlines(); RCT2_GLOBAL(0x009DEA50, sint16) = w->number; - window_invalidate(w); + gfx_invalidate_screen(); } } } @@ -724,6 +723,7 @@ void window_staff_unknown_05(){ void window_staff_stats_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update_by_class(w, (rct_windowclass)WC_STAFF); if (window_staff_page_widgets[w->page] != w->widgets){ w->widgets = window_staff_page_widgets[w->page]; @@ -756,6 +756,7 @@ void window_staff_stats_invalidate(){ void window_staff_options_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update_by_class(w, (rct_windowclass)WC_STAFF); if (window_staff_page_widgets[w->page] != w->widgets){ w->widgets = window_staff_page_widgets[w->page]; @@ -828,6 +829,7 @@ void window_staff_options_invalidate(){ void window_staff_overview_invalidate(){ rct_window* w; window_get_register(w); + colour_scheme_update_by_class(w, (rct_windowclass)WC_STAFF); if (window_staff_page_widgets[w->page] != w->widgets){ w->widgets = window_staff_page_widgets[w->page]; @@ -907,7 +909,7 @@ void window_staff_overview_paint(){ RCT2_GLOBAL(0x13CE952 + 4, uint32) = argument2; rct_widget* widget = &w->widgets[WIDX_BTM_LABEL]; int x = (widget->left + widget->right) / 2 + w->x; - int y = w->y + widget->top - 1; + int y = w->y + widget->top; int width = widget->right - widget->left; gfx_draw_string_centred_clipped(dpi, 1191, (void*)0x13CE952, 0, x, y, width); } @@ -1004,6 +1006,8 @@ void window_staff_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ ebx |= (peep->hat_colour << 19) | 0x20000000; gfx_draw_sprite(clip_dpi, ebx, x, y, 0); } + + rct2_free(clip_dpi); } /* rct2: 0x6BE7C6 */ @@ -1083,9 +1087,9 @@ void window_staff_overview_tool_update(){ RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; - int z; - get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &z, NULL); - if (z == 0) + int interactionType; + get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_NONE, NULL, NULL, &interactionType, NULL, NULL); + if (interactionType == VIEWPORT_INTERACTION_ITEM_NONE) return; x--; @@ -1114,11 +1118,11 @@ void window_staff_overview_tool_down(){ if (widgetIndex == WIDX_PICKUP){ - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - dest_y += 16; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + rct_map_element *mapElement; + footpath_get_coordinates_from_pos(x, y + 16, &dest_x, &dest_y, NULL, &mapElement); - if (dest_x == 0x8000)return; + if (dest_x == (sint16)0x8000)return; // Set the coordinate of destination to be exactly // in the middle of a tile. @@ -1128,9 +1132,9 @@ void window_staff_overview_tool_down(){ int tile_y = dest_y & 0xFFE0; int tile_x = dest_x & 0xFFE0; - int dest_z = ((uint8*)edx)[2] * 8 + 16; + int dest_z = mapElement->base_height * 8 + 16; - if (!sub_664F72(tile_x, tile_y, dest_z)){ + if (!map_is_location_owned(tile_x, tile_y, dest_z)){ window_error_open(0x785, -1); return; } @@ -1156,18 +1160,18 @@ void window_staff_overview_tool_down(){ peep_window_state_update(peep); peep->action = 0xFF; peep->var_6D = 0; - peep->var_70 = 0; - peep->var_6E = 0; + peep->action_sprite_image_offset = 0; + peep->action_sprite_type = 0; peep->var_C4 = 0; tool_cancel(); RCT2_GLOBAL(0x9DE550, sint32) = -1; } else if (widgetIndex == WIDX_PATROL){ - int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; - RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + int dest_x, dest_y; + footpath_get_coordinates_from_pos(x, y, &dest_x, &dest_y, NULL, NULL); - if (dest_x == 0x8000)return; + if (dest_x == (sint16)0x8000)return; game_do_command(dest_x, 1, dest_y, w->number, GAME_COMMAND_SET_STAFF_PATROL, 0, 0); } @@ -1188,14 +1192,14 @@ void window_staff_overview_tool_abort(){ sprite_move(w->var_48C, peep->y, peep->z + 8, (rct_sprite*)peep); invalidate_sprite((rct_sprite*)peep); - if (peep->x != 0x8000){ + if (peep->x != (sint16)0x8000){ peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; peep_window_state_update(peep); peep->action = 0xFF; peep->var_6D = 0; - peep->var_70 = 0; - peep->var_6E = 0; + peep->action_sprite_image_offset = 0; + peep->action_sprite_type = 0; peep->var_C4 = 0; } @@ -1238,8 +1242,6 @@ void window_staff_overview_viewport_init_wrapper(){ /* rct2: 0x006BEDA3 */ void window_staff_viewport_init(rct_window* w){ - RCT2_CALLPROC_X(0x006BEDA3, 0, 0, 0, 0, (int)w, 0, 0); - if (w->page != WINDOW_STAFF_OVERVIEW) return; sprite_focus focus; @@ -1277,7 +1279,7 @@ void window_staff_viewport_init(rct_window* w){ viewport_flags |= VIEWPORT_FLAG_GRIDLINES; } - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_invalidate_call(w); w->viewport_focus_sprite.sprite_id = focus.sprite_id; w->viewport_focus_sprite.type = focus.type; @@ -1316,9 +1318,8 @@ void window_staff_options_mousedown(int widgetIndex, rct_window* w, rct_widget* init_scenery(); int ebx = 0; - for (int i = 0; i < 19;++i){ - sint16* ebp = RCT2_ADDRESS(0xF64F2C, sint16*)[i]; - if (*ebp != -1){ + for (int i = 0; i < 19; i++) { + if (window_scenery_tab_entries[i][0] != -1) { rct_scenery_set_entry* scenery_entry = g_scenerySetEntries[i]; ebx |= scenery_entry->var_10A; } @@ -1356,7 +1357,7 @@ void window_staff_options_mousedown(int widgetIndex, rct_window* w, rct_widget* int y = widget->top + w->y; int extray = widget->bottom - widget->top + 1; int width = widget->right - widget->left - 3; - window_dropdown_show_text_custom_width(x, y, extray, w->colours[1], 0x80, no_entries, width); + window_dropdown_show_text_custom_width(x, y, extray, w->colours[1], DROPDOWN_FLAG_STAY_OPEN, no_entries, width); // See above note. gDropdownItemsChecked = item_checked; @@ -1381,4 +1382,4 @@ void window_staff_options_dropdown() int costume = (RCT2_ADDRESS(0xF4391B, uint8)[dropdownIndex] - 4) | 0x80; game_do_command(peep->x, (costume << 8) | 1, peep->y, w->number, GAME_COMMAND_SET_STAFF_ORDER, (int)peep, 0); -} \ No newline at end of file +} diff --git a/src/windows/staff_fire_prompt.c b/src/windows/staff_fire_prompt.c index f39248d39e..dcf4ae0c28 100644 --- a/src/windows/staff_fire_prompt.c +++ b/src/windows/staff_fire_prompt.c @@ -27,6 +27,7 @@ #include "../peep/staff.h" #include "../sprites.h" #include "../world/sprite.h" +#include "../interface/themes.h" #define WW 200 #define WH 100 @@ -51,6 +52,7 @@ static rct_widget window_staff_fire_widgets[] = { static void window_staff_fire_emptysub(){} static void window_staff_fire_mouseup(); +static void window_staff_fire_invalidate(); static void window_staff_fire_paint(); //0x9A3F7C @@ -80,7 +82,7 @@ static void* window_staff_fire_events[] = { window_staff_fire_emptysub, window_staff_fire_emptysub, window_staff_fire_emptysub, - window_staff_fire_emptysub, + window_staff_fire_invalidate, window_staff_fire_paint, window_staff_fire_emptysub }; @@ -91,21 +93,15 @@ void window_staff_fire_prompt_open(rct_peep* peep){ return; } - // Find center of the screen. - int screen_height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); - int screen_width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - int x = screen_width / 2 - WW / 2; - int y = screen_height / 2 - WH / 2; - - rct_window* w = window_create(x, y, WW, WH, (uint32*)0x992C3C, 0x1A, 0); + rct_window* w = window_create_centred(WW, WH, (uint32*)0x992C3C, 0x1A, WF_TRANSPARENT); w->widgets = window_staff_fire_widgets; w->enabled_widgets |= (1 << WIDX_CLOSE) | (1 << WIDX_YES) | (1 << WIDX_CANCEL); window_init_scroll_widgets(w); - w->flags |= WF_TRANSPARENT; + colour_scheme_update(w); + w->number = peep->sprite_index; - w->colours[0] = 0x9A; } @@ -131,6 +127,14 @@ static void window_staff_fire_mouseup(){ } } +static void window_staff_fire_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + /** * * rct2: 0x006C0AF2 diff --git a/src/windows/staff_list.c b/src/windows/staff_list.c index a173993971..18014ac40e 100644 --- a/src/windows/staff_list.c +++ b/src/windows/staff_list.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../drawing/drawing.h" #include "../input.h" @@ -30,6 +31,8 @@ #include "../peep/staff.h" #include "../world/sprite.h" #include "dropdown.h" +#include "../interface/themes.h" +#include "../sprites.h" enum { WINDOW_STAFF_LIST_TAB_HANDYMEN, @@ -38,6 +41,8 @@ enum { WINDOW_STAFF_LIST_TAB_ENTERTAINERS } WINDOW_STAFF_LIST_TAB; +bool _quick_fire_mode = false; + static void window_staff_list_emptysub() { } static void window_staff_list_close(); static void window_staff_list_mouseup(); @@ -100,22 +105,24 @@ enum WINDOW_STAFF_LIST_WIDGET_IDX { WIDX_STAFF_LIST_HIRE_BUTTON, WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON, WIDX_STAFF_LIST_MAP, + WIDX_STAFF_LIST_QUICK_FIRE, }; static rct_widget window_staff_list_widgets[] = { - { WWT_FRAME, 0, 0, 319, 0, 269, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 318, 1, 14, STR_STAFF, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button - { WWT_RESIZE, 1, 0, 319, 43, 269, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_STAFF_HANDYMEN_TAB_TIP }, // handymen tab - { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, STR_STAFF_MECHANICS_TAB_TIP }, // mechanics tab - { WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, STR_STAFF_SECURITY_TAB_TIP }, // security guards tab - { WWT_TAB, 1, 96, 126, 17, 43, 0x02000144E, STR_STAFF_ENTERTAINERS_TAB_TIP }, // entertainers tab - { WWT_SCROLL, 1, 3, 316, 72, 266, 3, STR_NONE }, // staff list - { WWT_COLORBTN, 1, 130, 141, 58, 69, STR_NONE, STR_UNIFORM_COLOUR_TIP }, // uniform color picker - { WWT_DROPDOWN_BUTTON, 0, 165, 309, 17, 29, STR_NONE, STR_HIRE_STAFF_TIP }, // hire button - { WWT_FLATBTN, 1, 267, 290, 46, 69, 5175, STR_SHOW_PATROL_AREA_TIP }, // show staff patrol area tool - { WWT_FLATBTN, 1, 291, 314, 46, 69, 5192, STR_SHOW_STAFF_ON_MAP_TIP }, // show staff on map button + { WWT_FRAME, 0, 0, 319, 0, 269, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 318, 1, 14, STR_STAFF, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button + { WWT_RESIZE, 1, 0, 319, 43, 269, 0x0FFFFFFFF, STR_NONE }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_STAFF_HANDYMEN_TAB_TIP }, // handymen tab + { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, STR_STAFF_MECHANICS_TAB_TIP }, // mechanics tab + { WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, STR_STAFF_SECURITY_TAB_TIP }, // security guards tab + { WWT_TAB, 1, 96, 126, 17, 43, 0x02000144E, STR_STAFF_ENTERTAINERS_TAB_TIP }, // entertainers tab + { WWT_SCROLL, 1, 3, 316, 72, 266, 3, STR_NONE }, // staff list + { WWT_COLORBTN, 1, 130, 141, 58, 69, STR_NONE, STR_UNIFORM_COLOUR_TIP }, // uniform color picker + { WWT_DROPDOWN_BUTTON, 0, 165, 309, 17, 29, STR_NONE, STR_HIRE_STAFF_TIP }, // hire button + { WWT_FLATBTN, 1, 267, 290, 46, 69, 5175, STR_SHOW_PATROL_AREA_TIP }, // show staff patrol area tool + { WWT_FLATBTN, 1, 291, 314, 46, 69, 5192, STR_SHOW_STAFF_ON_MAP_TIP }, // show staff on map button + { WWT_FLATBTN, 1, 243, 266, 46, 69, SPR_DEMOLISH, 5300 }, // quick fire staff { WIDGETS_END }, }; @@ -144,7 +151,7 @@ void window_staff_list_open() if (window != NULL) return; - window = window_create_auto_pos(320, 270, (uint32*)window_staff_list_events, WC_STAFF_LIST, 0x0400); + window = window_create_auto_pos(320, 270, (uint32*)window_staff_list_events, WC_STAFF_LIST, WF_10 | WF_RESIZABLE); window->widgets = window_staff_list_widgets; window->enabled_widgets = (1 << WIDX_STAFF_LIST_CLOSE) | @@ -155,7 +162,8 @@ void window_staff_list_open() (1 << WIDX_STAFF_LIST_HIRE_BUTTON) | (1 << WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER) | (1 << WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON) | - (1 << WIDX_STAFF_LIST_MAP); + (1 << WIDX_STAFF_LIST_MAP) | + (1 << WIDX_STAFF_LIST_QUICK_FIRE); window_init_scroll_widgets(window); RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short) = -1; @@ -166,10 +174,7 @@ void window_staff_list_open() window->min_height = 270; window->max_width = 500; window->max_height = 450; - window->flags |= WF_RESIZABLE; - window->colours[0] = 1; - window->colours[1] = 4; - window->colours[2] = 4; + _quick_fire_mode = false; } void window_staff_list_cancel_tools(rct_window *w) { @@ -231,6 +236,10 @@ static void window_staff_list_mouseup() case WIDX_STAFF_LIST_MAP: window_map_open(); break; + case WIDX_STAFF_LIST_QUICK_FIRE: + _quick_fire_mode ^= 1; + window_invalidate(w); + break; } } @@ -315,13 +324,13 @@ void window_staff_list_update(rct_window *w) w->list_information_type = 0; } else { widget_invalidate(w, WIDX_STAFF_LIST_HANDYMEN_TAB + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)); - RCT2_GLOBAL(0x009AC861, uint16) |= 2; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 2); FOR_ALL_PEEPS(spriteIndex, peep) { if (peep->type == PEEP_TYPE_STAFF) { - peep->var_0C &= 0xFDFF; + peep->var_0C &= ~0x200; if (peep->staff_type == RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)) { - peep->var_0C &= 0x200; + peep->var_0C |= 0x200; } } } @@ -350,8 +359,9 @@ void window_staff_list_toolabort() { * * rct2: 0x006BDBE6 */ -void window_staff_list_scrollgetsize() { - int spriteIndex; +void window_staff_list_scrollgetsize() +{ + int i, width, height, spriteIndex; rct_peep *peep; rct_window *w; @@ -370,8 +380,8 @@ void window_staff_list_scrollgetsize() { window_invalidate(w); } - int scrollHeight = staffCount * 10; - int i = scrollHeight - window_staff_list_widgets[WIDX_STAFF_LIST_LIST].bottom + window_staff_list_widgets[WIDX_STAFF_LIST_LIST].top + 21; + height = staffCount * 10; + i = height - window_staff_list_widgets[WIDX_STAFF_LIST_LIST].bottom + window_staff_list_widgets[WIDX_STAFF_LIST_LIST].top + 21; if (i < 0) i = 0; if (i < w->scrolls[0].v_top) { @@ -379,17 +389,8 @@ void window_staff_list_scrollgetsize() { window_invalidate(w); } - #ifdef _MSC_VER - __asm mov ecx, 420 - #else - __asm__("mov ecx, 420 "); - #endif - - #ifdef _MSC_VER - __asm mov edx, scrollHeight - #else - __asm__("mov edx, %[scrollHeight] " : [scrollHeight] "+m" (scrollHeight)); - #endif + width = 420; + window_scrollsize_set_registers(width, height); } /** @@ -398,11 +399,11 @@ void window_staff_list_scrollgetsize() { */ void window_staff_list_scrollmousedown() { int i, spriteIndex; - short x, y; + short x, y, scrollIndex; rct_window *w; rct_peep *peep; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); i = y / 10; FOR_ALL_PEEPS(spriteIndex, peep) { @@ -413,7 +414,10 @@ void window_staff_list_scrollmousedown() { continue; if (i == 0) { - window_staff_open(peep); + if (_quick_fire_mode) + game_do_command(peep->x, 1, peep->y, spriteIndex, GAME_COMMAND_FIRE_STAFF_MEMBER, 0, 0); + else + window_staff_open(peep); break; } @@ -427,10 +431,10 @@ void window_staff_list_scrollmousedown() { */ void window_staff_list_scrollmouseover() { int i; - short x, y; + short x, y, scrollIndex; rct_window *w; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); i = y / 10; if (i != RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short)) { @@ -457,6 +461,7 @@ void window_staff_list_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); int pressed_widgets = w->pressed_widgets & 0xFFFFFF0F; uint8 tabIndex = RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8); @@ -472,6 +477,10 @@ void window_staff_list_invalidate() ((uint32)RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[tabIndex] << 19) + 0x600013C3; } + if (_quick_fire_mode) + w->pressed_widgets |= (1 << WIDX_STAFF_LIST_QUICK_FIRE); + else + w->pressed_widgets &= ~(1 << WIDX_STAFF_LIST_QUICK_FIRE); window_staff_list_widgets[WIDX_STAFF_LIST_BACKGROUND].right = w->width - 1; window_staff_list_widgets[WIDX_STAFF_LIST_BACKGROUND].bottom = w->height - 1; @@ -608,11 +617,11 @@ void window_staff_list_scrollpaint() } if (y + 11 >= dpi->y) { - int format = 0x4A7; + int format = (_quick_fire_mode ? 5298 : 1191); if (i == RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short)) { gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031); - format = 0x4A9; + format = (_quick_fire_mode ? 5299 : 1193); } RCT2_GLOBAL(0x013CE952, uint16) = peep->name_string_idx; @@ -651,4 +660,4 @@ void window_staff_list_scrollpaint() i++; } } -} \ No newline at end of file +} diff --git a/src/windows/text_input.c b/src/windows/text_input.c index cba850a4f5..c6dcfd9008 100644 --- a/src/windows/text_input.c +++ b/src/windows/text_input.c @@ -27,14 +27,13 @@ #include "../addresses.h" #include "../config.h" -#include "../platform/osinterface.h" +#include "../platform/platform.h" #include "../interface/window.h" #include "../interface/widget.h" #include "../localisation/localisation.h" #define WW 250 #define WH 90 -#define MAX_TEXTINPUT 32 enum WINDOW_TEXT_INPUT_WIDGET_IDX { WIDX_BACKGROUND, @@ -58,8 +57,9 @@ static void window_text_input_emptysub(){} static void window_text_input_mouseup(); static void window_text_input_paint(); static void window_text_input_text(int key, rct_window* w); -static void window_text_input_update(rct_window* w); +static void window_text_input_update7(); static void window_text_input_close(); +static void window_text_input_invalidate(); //0x9A3F7C static void* window_text_input_events[] = { @@ -69,8 +69,8 @@ static void* window_text_input_events[] = { window_text_input_emptysub, window_text_input_emptysub, window_text_input_emptysub, - window_text_input_update, window_text_input_emptysub, + window_text_input_update7, window_text_input_emptysub, window_text_input_emptysub, window_text_input_emptysub, @@ -88,52 +88,133 @@ static void* window_text_input_events[] = { window_text_input_emptysub, window_text_input_emptysub, window_text_input_emptysub, - window_text_input_emptysub, + window_text_input_invalidate, window_text_input_paint, window_text_input_emptysub }; int input_text_description; -char text_input[MAX_TEXTINPUT] = { 0 }; +char text_input[512] = { 0 }; rct_windowclass calling_class = 0; rct_windownumber calling_number = 0; int calling_widget = 0; +int _maxInputLength; + +void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, rct_string_id existing_text, uint32 existing_args, int maxLength) +{ + _maxInputLength = maxLength; -void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, rct_string_id existing_text, uint32 existing_args){ window_close_by_class(WC_TEXTINPUT); + // Clear the text input buffer + memset(text_input, 0, maxLength); + + // Enter in the the text input buffer any existing + // text. + if (existing_text != (rct_string_id)STR_NONE) + format_string(text_input, existing_text, &existing_args); + + // In order to prevent strings that exceed the maxLength + // from crashing the game. + text_input[maxLength - 1] = '\0'; + + // This is the text displayed above the input box + input_text_description = description; + + // Work out the existing size of the window + char wrapped_string[512]; + strcpy(wrapped_string, text_input); + + int no_lines = 0, font_height = 0; + + // String length needs to add 12 either side of box + // +13 for cursor when max length. + gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); + + int height = no_lines * 10 + WH; + // Window will be in the center of the screen - rct_window* w = window_create( - (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2) - WW / 2, - (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) / 2) - WH / 2, + rct_window* w = window_create_centred( WW, - WH, + height, (uint32*)window_text_input_events, WC_TEXTINPUT, - 0); + WF_STICK_TO_FRONT + ); w->widgets = window_text_input_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1<classification; calling_number = call_w->number; calling_widget = call_widget; - osinterface_start_text_input(text_input, MAX_TEXTINPUT); + platform_start_text_input(text_input, maxLength); + + window_init_scroll_widgets(w); + w->colours[0] = call_w->colours[0]; + w->colours[1] = call_w->colours[1]; + w->colours[2] = call_w->colours[2]; +} + +void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, utf8string existing_text, int maxLength) +{ + _maxInputLength = maxLength; + + window_close_by_class(WC_TEXTINPUT); + + // Clear the text input buffer + memset(text_input, 0, maxLength); + + // Enter in the the text input buffer any existing + // text. + if (existing_text != NULL) + strncpy(text_input, existing_text, maxLength); + + // In order to prevent strings that exceed the maxLength + // from crashing the game. + text_input[maxLength - 1] = '\0'; + + // This is the text displayed above the input box + input_text_description = description; + + // Work out the existing size of the window + char wrapped_string[512]; + strcpy(wrapped_string, text_input); + + int no_lines = 0, font_height = 0; + + // String length needs to add 12 either side of box + // +13 for cursor when max length. + gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); + + int height = no_lines * 10 + WH; + + // Window will be in the center of the screen + rct_window* w = window_create_centred( + WW, + height, + (uint32*)window_text_input_events, + WC_TEXTINPUT, + WF_STICK_TO_FRONT + ); + + w->widgets = window_text_input_widgets; + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_CANCEL) | (1 << WIDX_OKAY); + + window_text_input_widgets[WIDX_TITLE].image = title; + + // Save calling window details so that the information + // can be passed back to the correct window & widget + calling_class = call_w->classification; + calling_number = call_w->number; + calling_widget = call_widget; + + platform_start_text_input(text_input, maxLength); window_init_scroll_widgets(w); w->colours[0] = call_w->colours[0]; @@ -155,19 +236,19 @@ static void window_text_input_mouseup(){ switch (widgetIndex){ case WIDX_CANCEL: case WIDX_CLOSE: - osinterface_stop_text_input(); + platform_stop_text_input(); // Pass back the text that has been entered. // ecx when zero means text input failed if (calling_w != NULL) - RCT2_CALLPROC_X(calling_w->event_handlers[WE_TEXT_INPUT], 0, 0, 0, calling_widget, (int)calling_w, (int)text_input, 0); + window_event_textinput_call(calling_w, calling_widget, NULL); window_close(w); break; case WIDX_OKAY: - osinterface_stop_text_input(); + platform_stop_text_input(); // Pass back the text that has been entered. // ecx when none zero means text input success if (calling_w != NULL) - RCT2_CALLPROC_X(calling_w->event_handlers[WE_TEXT_INPUT], 0, 0, 1, calling_widget, (int)calling_w, (int)text_input, 0); + window_event_textinput_call(calling_w, calling_widget, text_input); window_close(w); } } @@ -185,34 +266,66 @@ static void window_text_input_paint(){ int y = w->y + 25; - gfx_draw_string_centred(dpi, input_text_description, w->x + WW / 2, y, w->colours[1], 0); + int no_lines = 0; + int font_height = 0; + + + gfx_draw_string_centred(dpi, input_text_description, w->x + WW / 2, y, w->colours[1], &TextInputDescriptionArgs); y += 25; - gfx_fill_rect_inset(dpi, w->x + 10, y, w->x + WW - 10, y + 12, w->colours[1], 0x60); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + char wrapped_string[512]; + strcpy(wrapped_string, text_input); + + // String length needs to add 12 either side of box + // +13 for cursor when max length. + gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); + + gfx_fill_rect_inset(dpi, w->x + 10, y, w->x + WW - 10, y + 10 * (no_lines + 1) + 3, w->colours[1], 0x60); y += 1; - gfx_draw_string(dpi, text_input, w->colours[1], w->x + 12, y); - // Make a copy of the string for measuring the width. - char temp_string[32] = { 0 }; - memcpy(temp_string, text_input, gTextInputCursorPosition); - - int x = w->x + 13 + gfx_get_string_width(temp_string); + char* wrap_pointer = wrapped_string; + int char_count = 0; + uint8 cur_drawn = 0; - int width = 6; - if ((uint32)gTextInputCursorPosition < strlen(text_input)){ - // Make a new 1 character wide string for measuring the width - // of the character that the cursor is under. - temp_string[1] = '\0'; - temp_string[0] = text_input[gTextInputCursorPosition]; - width = max(gfx_get_string_width(temp_string) - 2, 4); - } + for (int line = 0; line <= no_lines; ++line){ + gfx_draw_string(dpi, wrap_pointer, w->colours[1], w->x + 12, y); - // Draw the cursor - y += 9; - if (w->frame_no > 15){ - gfx_fill_rect(dpi, x, y, x + width, y, w->colours[1]); + int string_length = get_string_length(wrap_pointer); + + if (!cur_drawn && (gTextInputCursorPosition <= char_count + string_length)){ + // Make a copy of the string for measuring the width. + char temp_string[512] = { 0 }; + memcpy(temp_string, wrap_pointer, gTextInputCursorPosition - char_count); + int cur_x = w->x + 13 + gfx_get_string_width(temp_string); + + int width = 6; + if ((uint32)gTextInputCursorPosition < strlen(text_input)){ + // Make a new 1 character wide string for measuring the width + // of the character that the cursor is under. + temp_string[1] = '\0'; + temp_string[0] = text_input[gTextInputCursorPosition]; + width = max(gfx_get_string_width(temp_string) - 2, 4); + } + + if (w->frame_no > 15){ + uint8 colour = RCT2_ADDRESS(0x0141FC48, uint8)[w->colours[1] * 8]; + gfx_fill_rect(dpi, cur_x, y + 9, cur_x + width, y + 9, colour + 5); + } + + cur_drawn++; + } + + wrap_pointer += string_length + 1; + + if (text_input[char_count + string_length] == ' ')char_count++; + char_count += string_length; + + y += 10; } } @@ -220,24 +333,28 @@ static void window_text_input_paint(){ static void window_text_input_text(int key, rct_window* w){ int text = key; - char new_char = osinterface_scancode_to_rct_keycode(0xFF&key); + char new_char = platform_scancode_to_rct_keycode(0xFF&key); // If the return button is pressed stop text input if (new_char == '\r'){ - osinterface_stop_text_input(); + platform_stop_text_input(); window_close(w); rct_window* calling_w = window_find_by_number(calling_class, calling_number); // Pass back the text that has been entered. // ecx when none zero means text input success if (calling_w) - RCT2_CALLPROC_X(calling_w->event_handlers[WE_TEXT_INPUT], 0, 0, 1, calling_widget, (int)calling_w, (int)text_input, 0); + window_event_textinput_call(calling_w, calling_widget, text_input); } window_invalidate(w); } -void window_text_input_update(rct_window* w) +void window_text_input_update7() { + rct_window* w; + + window_get_register(w); + rct_window* calling_w = window_find_by_number(calling_class, calling_number); // If the calling window is closed then close the text // input window. @@ -251,8 +368,41 @@ void window_text_input_update(rct_window* w) window_invalidate(w); } -static void window_text_input_close(){ +static void window_text_input_close() +{ // Make sure that we take it out of the text input // mode otherwise problems may occur. - osinterface_stop_text_input(); + platform_stop_text_input(); +} + +static void window_text_input_invalidate(){ + rct_window* w; + + window_get_register(w); + + // Work out the existing size of the window + char wrapped_string[512]; + strcpy(wrapped_string, text_input); + + int no_lines = 0, font_height = 0; + + // String length needs to add 12 either side of box + // +13 for cursor when max length. + gfx_wrap_string(wrapped_string, WW - (24 + 13), &no_lines, &font_height); + + int height = no_lines * 10 + WH; + + // Change window size if required. + if (height != w->height) { + window_invalidate(w); + window_set_resize(w, WW, height, WW, height); + } + + window_text_input_widgets[WIDX_OKAY].top = height - 21; + window_text_input_widgets[WIDX_OKAY].bottom = height - 10; + + window_text_input_widgets[WIDX_CANCEL].top = height - 21; + window_text_input_widgets[WIDX_CANCEL].bottom = height - 10; + + window_text_input_widgets[WIDX_BACKGROUND].bottom = height - 1; } \ No newline at end of file diff --git a/src/windows/themes.c b/src/windows/themes.c new file mode 100644 index 0000000000..265da25fb9 --- /dev/null +++ b/src/windows/themes.c @@ -0,0 +1,958 @@ +/***************************************************************************** +* Copyright (c) 2014 Maciek Baron, Dniel Tar +* 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 "../config.h" +#include "../game.h" +#include "../drawing/drawing.h" +#include "../input.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../peep/staff.h" +#include "../world/sprite.h" +#include "../sprites.h" +#include "dropdown.h" +#include "../interface/themes.h" +#include "error.h" + +enum { + WINDOW_THEMES_TAB_SETTINGS, + WINDOW_THEMES_TAB_MAIN_UI, + WINDOW_THEMES_TAB_PARK, + WINDOW_THEMES_TAB_TOOLS, + WINDOW_THEMES_TAB_RIDES_PEEPS, + WINDOW_THEMES_TAB_EDITORS, + WINDOW_THEMES_TAB_MISC, + WINDOW_THEMES_TAB_PROMPTS, + WINDOW_THEMES_TAB_FEATURES, + WINDOW_THEMES_TAB_COUNT +} WINDOW_THEMES_TAB; + +static void window_themes_emptysub() { } +static void window_themes_close(); +static void window_themes_mouseup(); +static void window_themes_resize(); +static void window_themes_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_themes_dropdown(); +static void window_themes_update(rct_window *w); +static void window_themes_scrollgetsize(); +static void window_themes_scrollmousedown(); +static void window_themes_scrollmouseover(); +static void window_themes_textinput(); +static void window_themes_tooltip(); +static void window_themes_invalidate(); +static void window_themes_paint(); +static void window_themes_scrollpaint(); +static void window_themes_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); + +static void* window_themes_events[] = { + window_themes_close, + window_themes_mouseup, + window_themes_resize, + window_themes_mousedown, + window_themes_dropdown, + window_themes_emptysub, + window_themes_update, + window_themes_emptysub, + window_themes_emptysub, + window_themes_emptysub, + window_themes_emptysub, + window_themes_emptysub, + window_themes_emptysub, + window_themes_emptysub, + window_themes_emptysub, + window_themes_scrollgetsize, + window_themes_scrollmousedown, + window_themes_emptysub, + window_themes_scrollmouseover, + window_themes_textinput, + window_themes_emptysub, + window_themes_emptysub, + window_themes_tooltip, + window_themes_emptysub, + window_themes_emptysub, + window_themes_invalidate, + window_themes_paint, + window_themes_scrollpaint, +}; + +enum WINDOW_STAFF_LIST_WIDGET_IDX { + WIDX_THEMES_BACKGROUND, + WIDX_THEMES_TITLE, + WIDX_THEMES_CLOSE, + WIDX_THEMES_TAB_CONTENT_PANEL, + WIDX_THEMES_SETTINGS_TAB, + WIDX_THEMES_MAIN_UI_TAB, + WIDX_THEMES_PARK_TAB, + WIDX_THEMES_TOOLS_TAB, + WIDX_THEMES_RIDE_PEEPS_TAB, + WIDX_THEMES_EDITORS_TAB, + WIDX_THEMES_MISC_TAB, + WIDX_THEMES_PROMPTS_TAB, + WIDX_THEMES_FEATURES_TAB, + WIDX_THEMES_PRESETS, + WIDX_THEMES_PRESETS_DROPDOWN, + WIDX_THEMES_DUPLICATE_BUTTON, + WIDX_THEMES_DELETE_BUTTON, + WIDX_THEMES_RENAME_BUTTON, + WIDX_THEMES_COLORBTN_MASK, + WIDX_THEMES_LIST, + WIDX_THEMES_RCT1_RIDE_LIGHTS, + WIDX_THEMES_RCT1_PARK_LIGHTS, + WIDX_THEMES_RCT1_SCENARIO_FONT +}; + +static rct_widget window_themes_widgets[] = { + { WWT_FRAME, 0, 0, 319, 0, 106, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 318, 1, 14, 5244, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button + { WWT_RESIZE, 1, 0, 319, 43, 106, 0x0FFFFFFFF, STR_NONE }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, 5235 }, // settings tab + { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, 5228 }, // main ui tab + { WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, 5229 }, // park tab + { WWT_TAB, 1, 96, 126, 17, 43, 0x02000144E, 5230 }, // tools tab + { WWT_TAB, 1, 127, 157, 17, 43, 0x02000144E, 5231 }, // rides and peeps tab + { WWT_TAB, 1, 158, 188, 17, 43, 0x02000144E, 5232 }, // editors tab + { WWT_TAB, 1, 189, 219, 17, 43, 0x02000144E, 5233 }, // misc tab + { WWT_TAB, 1, 220, 250, 17, 43, 0x02000144E, 5234 }, // prompts tab + { WWT_TAB, 1, 251, 281, 17, 43, 0x02000144E, 5281 }, // features tab + { WWT_DROPDOWN, 1, 125, 299, 60, 71, STR_NONE, STR_NONE }, // Preset colour schemes + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 61, 70, 876, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 10, 100, 82, 93, 5239, 5257 }, // Duplicate button + { WWT_DROPDOWN_BUTTON, 1, 110, 200, 82, 93, 3349, 5258 }, // Delete button + { WWT_DROPDOWN_BUTTON, 1, 210, 300, 82, 93, 3348, 5259 }, // Rename button + { WWT_COLORBTN, 1, 0, 0, 0, 0, STR_NONE, STR_NONE }, // color button mask + { WWT_SCROLL, 1, 3, 316, 60, 103, 2, STR_NONE }, // staff list + { WWT_CHECKBOX, 1, 10, 299, 54, 65, 5282, STR_NONE }, // rct1 ride lights + { WWT_CHECKBOX, 1, 10, 299, 69, 80, 5283, STR_NONE }, // rct1 park lights + { WWT_CHECKBOX, 1, 10, 299, 84, 95, 5284, STR_NONE }, // rct1 scenario font + { WIDGETS_END }, +}; + +static int window_themes_tab_animation_loops[] = { + 32, + 32, + 1, + 1, + 64, + 32, + 8, + 14, + 38 +}; +static int window_themes_tab_animation_divisor[] = { + 4, + 4, + 1, + 1, + 4, + 2, + 2, + 2, + 2 +}; +static int window_themes_tab_sprites[] = { + 5221, + SPR_TAB_KIOSKS_AND_FACILITIES_0, + 5200, + SPR_G2_TAB_LAND, + SPR_TAB_RIDE_0, + 5205, + 5201, + SPR_TAB_STAFF_OPTIONS_0, + SPR_TAB_FINANCES_MARKETING_0 +}; + +static rct_windowclass window_themes_tab_1_classes[] = { + WC_TOP_TOOLBAR, + WC_BOTTOM_TOOLBAR, + WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR, + WC_EDITOR_TRACK_BOTTOM_TOOLBAR, + WC_TITLE_MENU, + WC_TITLE_EXIT, + WC_TITLE_OPTIONS, + WC_SCENARIO_SELECT +}; + +static rct_windowclass window_themes_tab_2_classes[] = { + WC_PARK_INFORMATION, + WC_FINANCES, + WC_NEW_CAMPAIGN, + WC_RESEARCH, + WC_MAP, + WC_VIEWPORT, + WC_RECENT_NEWS +}; + +static rct_windowclass window_themes_tab_3_classes[] = { + WC_LAND, + WC_WATER, + WC_CLEAR_SCENERY, + WC_LAND_RIGHTS, + WC_SCENERY, + WC_FOOTPATH, + WC_RIDE_CONSTRUCTION, + WC_TRACK_DESIGN_PLACE, + WC_CONSTRUCT_RIDE, + WC_TRACK_DESIGN_LIST +}; + +static rct_windowclass window_themes_tab_4_classes[] = { + WC_RIDE, + WC_RIDE_LIST, + WC_PEEP, + WC_GUEST_LIST, + WC_STAFF, + WC_STAFF_LIST, + WC_BANNER +}; + +static rct_windowclass window_themes_tab_5_classes[] = { + WC_EDITOR_OBJECT_SELECTION, + WC_EDITOR_INVENTION_LIST, + WC_EDITOR_SCENARIO_OPTIONS, + WC_EDTIOR_OBJECTIVE_OPTIONS, + WC_MAPGEN, + WC_MANAGE_TRACK_DESIGN, + WC_INSTALL_TRACK +}; + +static rct_windowclass window_themes_tab_6_classes[] = { + WC_CHEATS, + WC_THEMES, + WC_OPTIONS, + WC_KEYBOARD_SHORTCUT_LIST, + WC_CHANGE_KEYBOARD_SHORTCUT, + WC_LOADSAVE +}; + +static rct_windowclass window_themes_tab_7_classes[] = { + WC_SAVE_PROMPT, + WC_DEMOLISH_RIDE_PROMPT, + WC_FIRE_PROMPT, + WC_TRACK_DELETE_PROMPT, + WC_LOADSAVE_OVERWRITE_PROMPT +}; + +static uint8 _selected_tab = 0; +static sint16 _color_index_1 = -1; +static sint8 _color_index_2 = -1; +static const uint8 _row_height = 32; +static const uint8 _button_offset_x = 220; +static const uint8 _button_offset_y = 3; +static const uint8 _check_offset_y = 3 + 12 + 2; + +void window_themes_init_vars() +{ + _selected_tab = WINDOW_THEMES_TAB_SETTINGS; +} + +static theme_window_definition* get_colour_scheme_tab_definition() +{ + switch (_selected_tab) { + case 1: return theme_window_definition_get_by_class(window_themes_tab_1_classes[_color_index_1]); + case 2: return theme_window_definition_get_by_class(window_themes_tab_2_classes[_color_index_1]); + case 3: return theme_window_definition_get_by_class(window_themes_tab_3_classes[_color_index_1]); + case 4: return theme_window_definition_get_by_class(window_themes_tab_4_classes[_color_index_1]); + case 5: return theme_window_definition_get_by_class(window_themes_tab_5_classes[_color_index_1]); + case 6: return theme_window_definition_get_by_class(window_themes_tab_6_classes[_color_index_1]); + case 7: return theme_window_definition_get_by_class(window_themes_tab_7_classes[_color_index_1]); + } + return NULL; +} +static theme_window_definition* get_colour_scheme_tab_definition_by_index(int index) +{ + switch (_selected_tab) { + case 1: return theme_window_definition_get_by_class(window_themes_tab_1_classes[index]); + case 2: return theme_window_definition_get_by_class(window_themes_tab_2_classes[index]); + case 3: return theme_window_definition_get_by_class(window_themes_tab_3_classes[index]); + case 4: return theme_window_definition_get_by_class(window_themes_tab_4_classes[index]); + case 5: return theme_window_definition_get_by_class(window_themes_tab_5_classes[index]); + case 6: return theme_window_definition_get_by_class(window_themes_tab_6_classes[index]); + case 7: return theme_window_definition_get_by_class(window_themes_tab_7_classes[index]); + } + return NULL; +} +static theme_window* get_colour_scheme_tab() +{ + switch (_selected_tab) { + case 1: return theme_window_get_by_class(window_themes_tab_1_classes[_color_index_1]); + case 2: return theme_window_get_by_class(window_themes_tab_2_classes[_color_index_1]); + case 3: return theme_window_get_by_class(window_themes_tab_3_classes[_color_index_1]); + case 4: return theme_window_get_by_class(window_themes_tab_4_classes[_color_index_1]); + case 5: return theme_window_get_by_class(window_themes_tab_5_classes[_color_index_1]); + case 6: return theme_window_get_by_class(window_themes_tab_6_classes[_color_index_1]); + case 7: return theme_window_get_by_class(window_themes_tab_7_classes[_color_index_1]); + } + return NULL; +} +static theme_window* get_colour_scheme_tab_by_index(int index) +{ + switch (_selected_tab) { + case 1: return theme_window_get_by_class(window_themes_tab_1_classes[index]); + case 2: return theme_window_get_by_class(window_themes_tab_2_classes[index]); + case 3: return theme_window_get_by_class(window_themes_tab_3_classes[index]); + case 4: return theme_window_get_by_class(window_themes_tab_4_classes[index]); + case 5: return theme_window_get_by_class(window_themes_tab_5_classes[index]); + case 6: return theme_window_get_by_class(window_themes_tab_6_classes[index]); + case 7: return theme_window_get_by_class(window_themes_tab_7_classes[index]); + } + return NULL; +} + +static int get_colour_scheme_tab_count() +{ + switch (_selected_tab) { + case 1: return sizeof(window_themes_tab_1_classes); + case 2: return sizeof(window_themes_tab_2_classes); + case 3: return sizeof(window_themes_tab_3_classes); + case 4: return sizeof(window_themes_tab_4_classes); + case 5: return sizeof(window_themes_tab_5_classes); + case 6: return sizeof(window_themes_tab_6_classes); + case 7: return sizeof(window_themes_tab_7_classes); + } + return 0; +} + +/*static int get_colour_scheme_index() { + switch (_selected_tab) { + case 1: return theme_window_get_index_by_class(window_themes_tab_1_classes[_color_index_1]); + case 2: return theme_window_get_index_by_class(window_themes_tab_2_classes[_color_index_1]); + case 3: return theme_window_get_index_by_class(window_themes_tab_3_classes[_color_index_1]); + case 4: return theme_window_get_index_by_class(window_themes_tab_4_classes[_color_index_1]); + case 5: return theme_window_get_index_by_class(window_themes_tab_5_classes[_color_index_1]); + case 6: return theme_window_get_index_by_class(window_themes_tab_6_classes[_color_index_1]); + case 7: return theme_window_get_index_by_class(window_themes_tab_7_classes[_color_index_1]); + } + return -1; +}*/ + +static void window_themes_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) +{ + int sprite_idx; + + for (int i = 0; i < WINDOW_THEMES_TAB_COUNT; i++) { + sprite_idx = window_themes_tab_sprites[i]; + if (_selected_tab == i) + sprite_idx += w->frame_no / window_themes_tab_animation_divisor[_selected_tab]; + gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_THEMES_SETTINGS_TAB + i].left, w->y + w->widgets[WIDX_THEMES_SETTINGS_TAB + i].top, 0); + } +} + +void window_themes_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_class(WC_THEMES); + if (window != NULL) + return; + + window = window_create_auto_pos(320, 107, (uint32*)window_themes_events, WC_THEMES, WF_10 | WF_RESIZABLE); + window->widgets = window_themes_widgets; + window->enabled_widgets = + (1 << WIDX_THEMES_CLOSE) | + (1 << WIDX_THEMES_SETTINGS_TAB) | + (1 << WIDX_THEMES_MAIN_UI_TAB) | + (1 << WIDX_THEMES_PARK_TAB) | + (1 << WIDX_THEMES_TOOLS_TAB) | + (1 << WIDX_THEMES_RIDE_PEEPS_TAB) | + (1 << WIDX_THEMES_EDITORS_TAB) | + (1 << WIDX_THEMES_MISC_TAB) | + (1 << WIDX_THEMES_PROMPTS_TAB) | + (1 << WIDX_THEMES_FEATURES_TAB) | + (1 << WIDX_THEMES_COLORBTN_MASK) | + (1 << WIDX_THEMES_PRESETS) | + (1 << WIDX_THEMES_PRESETS_DROPDOWN) | + (1 << WIDX_THEMES_DUPLICATE_BUTTON) | + (1 << WIDX_THEMES_DELETE_BUTTON) | + (1 << WIDX_THEMES_RENAME_BUTTON) | + (1 << WIDX_THEMES_RCT1_RIDE_LIGHTS) | + (1 << WIDX_THEMES_RCT1_PARK_LIGHTS) | + (1 << WIDX_THEMES_RCT1_SCENARIO_FONT); + + window_themes_init_vars(); + + window_init_scroll_widgets(window); + window->list_information_type = 0; + _color_index_1 = -1; + _color_index_2 = -1; + window->min_width = 320; + window->min_height = 107; + window->max_width = 320; + window->max_height = 107; +} + +void window_themes_close() { + rct_window *w; + + window_get_register(w); +} + +static void window_themes_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_THEMES_CLOSE: + window_close(w); + break; + case WIDX_THEMES_DUPLICATE_BUTTON: + window_text_input_open(w, widgetIndex, 5239, 5240, 1170, (uint32)&gConfigThemes.presets[gCurrentTheme].name, 64); + break; + case WIDX_THEMES_DELETE_BUTTON: + if (gCurrentTheme >= 2) { + theme_delete_preset(gCurrentTheme); + } + else { + window_error_open(5241, STR_NONE); + } + break; + case WIDX_THEMES_RENAME_BUTTON: + if (gCurrentTheme >= 2) { + window_text_input_open(w, widgetIndex, 3348, 5240, 1170, (uint32)&gConfigThemes.presets[gCurrentTheme].name, 64); + } + else { + window_error_open(5241, STR_NONE); + } + break; + } +} + +static void window_themes_resize() +{ + rct_window *w; + + window_get_register(w); + + if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS) { + w->min_width = 320; + w->min_height = 107; + w->max_width = 320; + w->max_height = 107; + + if (w->width < w->min_width) { + w->width = w->min_width; + gfx_invalidate_screen(); + } + if (w->height < w->min_height) { + w->height = w->min_height; + gfx_invalidate_screen(); + } + if (w->width > w->max_width) { + w->width = w->max_width; + gfx_invalidate_screen(); + } + if (w->height > w->max_height) { + w->height = w->max_height; + gfx_invalidate_screen(); + } + } + else if (_selected_tab == WINDOW_THEMES_TAB_FEATURES) { + w->min_width = 320; + w->min_height = 107; + w->max_width = 320; + w->max_height = 107; + + if (w->width < w->min_width) { + w->width = w->min_width; + gfx_invalidate_screen(); + } + if (w->height < w->min_height) { + w->height = w->min_height; + gfx_invalidate_screen(); + } + if (w->width > w->max_width) { + w->width = w->max_width; + gfx_invalidate_screen(); + } + if (w->height > w->max_height) { + w->height = w->max_height; + gfx_invalidate_screen(); + } + } + else { + w->min_width = 320; + w->min_height = 270; + w->max_width = 320; + w->max_height = 450; + + if (w->width < w->min_width) { + w->width = w->min_width; + window_invalidate(w); + } + if (w->height < w->min_height) { + w->height = w->min_height; + window_invalidate(w); + } + if (w->width > w->max_width) { + w->width = w->max_width; + window_invalidate(w); + } + if (w->height > w->max_height) { + w->height = w->max_height; + window_invalidate(w); + } + } +} + +static void window_themes_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +{ + short newSelectedTab; + int num_items, i; + + switch (widgetIndex) { + case WIDX_THEMES_SETTINGS_TAB: + case WIDX_THEMES_MAIN_UI_TAB: + case WIDX_THEMES_PARK_TAB: + case WIDX_THEMES_TOOLS_TAB: + case WIDX_THEMES_RIDE_PEEPS_TAB: + case WIDX_THEMES_EDITORS_TAB: + case WIDX_THEMES_MISC_TAB: + case WIDX_THEMES_PROMPTS_TAB: + case WIDX_THEMES_FEATURES_TAB: + newSelectedTab = widgetIndex - WIDX_THEMES_SETTINGS_TAB; + if (_selected_tab == newSelectedTab) + break; + _selected_tab = (uint8)newSelectedTab; + w->scrolls[0].v_top = 0; + w->frame_no = 0; + window_event_resize_call(w); + window_invalidate(w); + break; + case WIDX_THEMES_PRESETS_DROPDOWN: + num_items = gConfigThemes.num_presets; + + widget--; + gDropdownItemsFormat[0] = 2777; + gDropdownItemsArgs[0] = (uint64)&gConfigThemes.presets[1].name; + gDropdownItemsFormat[1] = 2777; + gDropdownItemsArgs[1] = (uint64)&gConfigThemes.presets[0].name; + + for (i = 2; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint64)&gConfigThemes.presets[i].name; + } + + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + num_items, + widget->right - widget->left - 3 + ); + + if (gCurrentTheme == 0 || gCurrentTheme == 1) + gDropdownItemsChecked = 1 << (gCurrentTheme ^ 1); + else + gDropdownItemsChecked = 1 << (gCurrentTheme); + break; + case WIDX_THEMES_RCT1_RIDE_LIGHTS: + if (gCurrentTheme >= 2) { + theme_get_preset()->features.rct1_ride_lights ^= 1; + themes_save_preset(gCurrentTheme); + window_invalidate_all(); + } + else { + window_error_open(5241, STR_NONE); + } + break; + case WIDX_THEMES_RCT1_PARK_LIGHTS: + if (gCurrentTheme >= 2) { + theme_get_preset()->features.rct1_park_lights ^= 1; + themes_save_preset(gCurrentTheme); + window_invalidate_all(); + } + else { + window_error_open(5241, STR_NONE); + } + break; + case WIDX_THEMES_RCT1_SCENARIO_FONT: + if (gCurrentTheme >= 2) { + theme_get_preset()->features.rct1_scenario_font ^= 1; + themes_save_preset(gCurrentTheme); + window_invalidate_all(); + } + else { + window_error_open(5241, STR_NONE); + } + break; + } +} + +static void window_themes_dropdown() +{ + rct_window* w; + short widgetIndex, dropdownIndex; + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + switch (widgetIndex) { + case WIDX_THEMES_LIST: + if (dropdownIndex != -1) { + get_colour_scheme_tab()->colours[_color_index_2] = dropdownIndex | get_colour_scheme_tab()->colours[_color_index_2] & 0x80; + window_invalidate_all(); + _color_index_1 = -1; + _color_index_2 = -1; + + if (gCurrentTheme >= 2) + themes_save_preset(gCurrentTheme); + } + break; + case WIDX_THEMES_PRESETS_DROPDOWN: + if (dropdownIndex != -1) { + if (dropdownIndex == 0 || dropdownIndex == 1) + dropdownIndex ^= 1; + theme_change_preset(dropdownIndex); + } + config_save_default(); + break; + } + +} + +void window_themes_update(rct_window *w) +{ + w->frame_no++; + if (w->frame_no >= window_themes_tab_animation_loops[_selected_tab]) + w->frame_no = 0; + + widget_invalidate(w, WIDX_THEMES_SETTINGS_TAB + _selected_tab); + +} + +void window_themes_scrollgetsize() { + rct_window *w; + + window_get_register(w); + + if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS || _selected_tab == WINDOW_THEMES_TAB_FEATURES) + return; + + int scrollHeight = get_colour_scheme_tab_count() * _row_height; + int i = scrollHeight - window_themes_widgets[WIDX_THEMES_LIST].bottom + window_themes_widgets[WIDX_THEMES_LIST].top + 21; + if (i < 0) + i = 0; + if (i < w->scrolls[0].v_top) { + w->scrolls[0].v_top = i; + window_invalidate(w); + } + + #ifdef _MSC_VER + __asm mov ecx, 420 + #else + __asm__("mov ecx, 420 "); + #endif + + #ifdef _MSC_VER + __asm mov edx, scrollHeight + #else + __asm__("mov edx, %[scrollHeight] " : [scrollHeight] "+m" (scrollHeight)); + #endif +} + +void window_themes_scrollmousedown() { + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + if (y / _row_height < get_colour_scheme_tab_count()) { + int y2 = y % _row_height; + _color_index_1 = y / _row_height; + _color_index_2 = ((x - _button_offset_x) / 12); + if (_color_index_2 < get_colour_scheme_tab_definition()->num_colours) { + if (x >= _button_offset_x && x < _button_offset_x + 12 * 6 && y2 >= _button_offset_y && y2 < _button_offset_y + 11) { + if (gCurrentTheme >= 2) { + window_themes_widgets[WIDX_THEMES_COLORBTN_MASK].left = _button_offset_x + _color_index_2 * 12 + window_themes_widgets[WIDX_THEMES_LIST].left; + window_themes_widgets[WIDX_THEMES_COLORBTN_MASK].top = _color_index_1 * _row_height + _button_offset_y - w->scrolls[0].v_top + window_themes_widgets[WIDX_THEMES_LIST].top; + window_themes_widgets[WIDX_THEMES_COLORBTN_MASK].right = window_themes_widgets[WIDX_THEMES_COLORBTN_MASK].left + 12; + window_themes_widgets[WIDX_THEMES_COLORBTN_MASK].bottom = window_themes_widgets[WIDX_THEMES_COLORBTN_MASK].top + 12; + window_dropdown_show_colour(w, &(window_themes_widgets[WIDX_THEMES_COLORBTN_MASK]), w->colours[1], get_colour_scheme_tab()->colours[_color_index_2]); + widget_invalidate(w, WIDX_THEMES_LIST); + } + else { + window_error_open(5241, 5256); + } + } + else if (x >= _button_offset_x && x < _button_offset_x + 12 * 6 - 1 && y2 >= _check_offset_y && y2 < _check_offset_y + 11) { + if (gCurrentTheme >= 2) { + if (get_colour_scheme_tab()->colours[_color_index_2] & 0x80) { + get_colour_scheme_tab()->colours[_color_index_2] &= 0x7F; + } + else { + get_colour_scheme_tab()->colours[_color_index_2] |= 0x80; + } + themes_save_preset(gCurrentTheme); + window_invalidate_all(); + } + else { + window_error_open(5241, 5256); + } + } + } + } +} + +void window_themes_scrollmouseover() { + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + //if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS) + // return; +} + +static bool valid_characters(const char *name) +{ + for (int i = 0; name[i] != '\0'; i++) { + if (name[i] == '\\' || name[i] == '/' || name[i] == ':' || name[i] == '?' || name[i] == '*' || name[i] == '<' || name[i] == '>' || name[i] == '|') + return false; + } + return true; +} + +static void window_themes_textinput() +{ + rct_window *w; + short widgetIndex; + uint8 result; + char *text; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (!result || text[0] == 0) + return; + + switch (widgetIndex) { + case WIDX_THEMES_DUPLICATE_BUTTON: + case WIDX_THEMES_RENAME_BUTTON: + if (valid_characters(text)) { + bool nameTaken = false; + for (int i = 0; i < gConfigThemes.num_presets; i++) { + if (strcmp(gConfigThemes.presets[i].name, text) == 0) { + window_error_open(5242, STR_NONE); + nameTaken = true; + break; + } + } + if (!nameTaken) { + if (widgetIndex == WIDX_THEMES_DUPLICATE_BUTTON) { + theme_create_preset(gCurrentTheme, text); + } + else { + theme_rename_preset(gCurrentTheme, text); + } + config_save_default(); + window_invalidate(w); + } + } + else { + window_error_open(5243, STR_NONE); + } + break; + } +} + +void window_themes_tooltip() +{ + RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; +} + +void window_themes_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); + + int pressed_widgets = w->pressed_widgets & 0xFFFFE00F; + uint8 widgetIndex = _selected_tab + 4; + + w->pressed_widgets = pressed_widgets | (1 << widgetIndex); + + if (window_find_by_class(WC_DROPDOWN) == NULL) { + _color_index_1 = -1; + _color_index_2 = -1; + } + + window_themes_widgets[WIDX_THEMES_BACKGROUND].right = w->width - 1; + window_themes_widgets[WIDX_THEMES_BACKGROUND].bottom = w->height - 1; + window_themes_widgets[WIDX_THEMES_TAB_CONTENT_PANEL].right = w->width - 1; + window_themes_widgets[WIDX_THEMES_TAB_CONTENT_PANEL].bottom = w->height - 1; + window_themes_widgets[WIDX_THEMES_TITLE].right = w->width - 2; + window_themes_widgets[WIDX_THEMES_CLOSE].left = w->width - 2 - 0x0B; + window_themes_widgets[WIDX_THEMES_CLOSE].right = w->width - 2 - 0x0B + 0x0A; + window_themes_widgets[WIDX_THEMES_LIST].right = w->width - 4; + window_themes_widgets[WIDX_THEMES_LIST].bottom = w->height - 0x0F; + + + window_themes_widgets[WIDX_THEMES_LIST].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_RIDE_LIGHTS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_DELETE_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RENAME_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_PRESETS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].type = WWT_EMPTY; + + if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS) { + window_themes_widgets[WIDX_THEMES_LIST].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_RIDE_LIGHTS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_themes_widgets[WIDX_THEMES_DELETE_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_themes_widgets[WIDX_THEMES_RENAME_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_themes_widgets[WIDX_THEMES_PRESETS].type = WWT_DROPDOWN; + window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + } + else if (_selected_tab == WINDOW_THEMES_TAB_FEATURES) { + window_themes_widgets[WIDX_THEMES_LIST].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_RIDE_LIGHTS].type = WWT_CHECKBOX; + window_themes_widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WWT_CHECKBOX; + window_themes_widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WWT_CHECKBOX; + window_themes_widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_DELETE_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RENAME_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_PRESETS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].type = WWT_EMPTY; + + widget_set_checkbox_value(w, WIDX_THEMES_RCT1_RIDE_LIGHTS, theme_get_preset()->features.rct1_ride_lights); + widget_set_checkbox_value(w, WIDX_THEMES_RCT1_PARK_LIGHTS, theme_get_preset()->features.rct1_park_lights); + widget_set_checkbox_value(w, WIDX_THEMES_RCT1_SCENARIO_FONT, theme_get_preset()->features.rct1_scenario_font); + } + else { + window_themes_widgets[WIDX_THEMES_LIST].type = WWT_SCROLL; + window_themes_widgets[WIDX_THEMES_RCT1_RIDE_LIGHTS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_DELETE_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_RENAME_BUTTON].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_PRESETS].type = WWT_EMPTY; + window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].type = WWT_EMPTY; + } +} + +void window_themes_paint() { + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + // Widgets + window_draw_widgets(w, dpi); + window_themes_draw_tab_images(dpi, w); + + if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS) { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigThemes.presets[gCurrentTheme].name; + gfx_draw_string_left(dpi, 5238, NULL, w->colours[1], w->x + 10, w->y + window_themes_widgets[WIDX_THEMES_PRESETS].top + 1); + gfx_draw_string_left_clipped( + dpi, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, + w->colours[1], + w->x + window_themes_widgets[WIDX_THEMES_PRESETS].left + 1, + w->y + window_themes_widgets[WIDX_THEMES_PRESETS].top, + w->x + window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].left - window_themes_widgets[WIDX_THEMES_PRESETS].left - 4 + ); + } + else if (_selected_tab == WINDOW_THEMES_TAB_FEATURES) { + + } + else { + gfx_draw_string_left(dpi, 5236, w, w->colours[1], w->x + 6, 58 - 12 + w->y + 1); + gfx_draw_string_left(dpi, 5237, w, w->colours[1], w->x + 220, 58 - 12 + w->y + 1); + } +} + +/** +* +* rct2: 0x006BD785 +*/ +void window_themes_scrollpaint() +{ + int y; + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS || _selected_tab == WINDOW_THEMES_TAB_FEATURES) + return; + + if ((w->colours[1] & 0x80) == 0) + //gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ((char*)0x0141FC48)[w->colours[1] * 8]); + gfx_clear(dpi, ((char*)0x0141FC48)[w->colours[1] * 8] * 0x1010101); + y = 0; + for (int i = 0; i < get_colour_scheme_tab_count(); i++) { + if (y > dpi->y + dpi->height) { + break; + } + if (y + _row_height >= dpi->y) { + if (i + 1 < get_colour_scheme_tab_count()) { + int colour = w->colours[1]; + if (colour & 0x80) { + colour = RCT2_ADDRESS(0x009DEDF4, uint8)[colour]; + + colour = colour | 0x2000000; + gfx_fill_rect(dpi, 0, y + _row_height - 2, window_themes_widgets[WIDX_THEMES_LIST].right, y + _row_height - 2, colour + 1); + gfx_fill_rect(dpi, 0, y + _row_height - 1, window_themes_widgets[WIDX_THEMES_LIST].right, y + _row_height - 1, colour + 2); + } + else { + colour = RCT2_ADDRESS(0x0141FC47, uint8)[w->colours[1] * 8]; + gfx_fill_rect(dpi, 0, y + _row_height - 2, window_themes_widgets[WIDX_THEMES_LIST].right, y + _row_height - 2, colour); + colour = RCT2_ADDRESS(0x0141FC4B, uint8)[w->colours[1] * 8]; + gfx_fill_rect(dpi, 0, y + _row_height - 1, window_themes_widgets[WIDX_THEMES_LIST].right, y + _row_height - 1, colour); + } + } + + for (int j = 0; j < get_colour_scheme_tab_definition_by_index(i)->num_colours; j++) { + + gfx_draw_string_left(dpi, get_colour_scheme_tab_definition_by_index(i)->name, NULL, w->colours[1], 2, y + 4); + + uint32 image = ((get_colour_scheme_tab_by_index(i)->colours[j] & 0x7F) << 19) + 0x600013C3; + if (i == _color_index_1 && j == _color_index_2) { + image = ((get_colour_scheme_tab_by_index(i)->colours[j] & 0x7F) << 19) + 0x600013C4; + } + gfx_draw_sprite(dpi, image, _button_offset_x + 12 * j, y + _button_offset_y, 0); + + gfx_fill_rect_inset(dpi, _button_offset_x + 12 * j, y + _check_offset_y, _button_offset_x + 12 * j + 9, y + _check_offset_y + 10, w->colours[1], 0xE0); + if (get_colour_scheme_tab_by_index(i)->colours[j] & 0x80) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = -1; + gfx_draw_string(dpi, (char*)0x009DED72, w->colours[1] & 0x7F, _button_offset_x + 12 * j, y + _check_offset_y); + } + + } + } + + y += _row_height; + } +} diff --git a/src/windows/tile_inspector.c b/src/windows/tile_inspector.c new file mode 100644 index 0000000000..539b3a2f9b --- /dev/null +++ b/src/windows/tile_inspector.c @@ -0,0 +1,424 @@ +/***************************************************************************** +* 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 . +*****************************************************************************/ + +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../interface/viewport.h" +#include "../world/scenery.h" +#include "../world/map.h" +#include "../world/footpath.h" + +enum WINDOW_TILE_INSPECTOR_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_CONTENT_PANEL, + WIDX_SCROLL +}; + +#define WW 500 +#define WH 400 +#define MIN_WH 150 +#define MAX_WH 800 + +rct_widget window_tile_inspector_widgets[] = { + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_TILE_INSPECTOR_TITLE, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_RESIZE, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, STR_NONE }, // content panel + { WWT_SCROLL, 1, 3, WW - 3, 65, WH - 30, 2, STR_NONE }, // scroll area + { WIDGETS_END }, +}; + +static int window_tile_inspector_tile_x; +static int window_tile_inspector_tile_y; +static int window_tile_inspector_item_count; + +static void window_tile_inspector_emptysub() { } +static void window_tile_inspector_close(); +static void window_tile_inspector_tool_update(); +static void window_tile_inspector_tool_down(); +static void window_tile_inspector_tool_abort(); +static void window_tile_inspector_scrollgetsize(); +static void window_tile_inspector_scrollmouseover(); +static void window_tile_inspector_mouseup(); +static void window_tile_inspector_resize(); +static void window_tile_inspector_invalidate(); +static void window_tile_inspector_paint(); +static void window_tile_inspector_scrollpaint(); + +static void* window_tile_inspector_events[] = { + window_tile_inspector_close, + window_tile_inspector_mouseup, + window_tile_inspector_resize, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_tool_update, + window_tile_inspector_tool_down, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_tool_abort, + window_tile_inspector_emptysub, + window_tile_inspector_scrollgetsize, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_scrollmouseover, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_emptysub, + window_tile_inspector_invalidate, + window_tile_inspector_paint, + window_tile_inspector_scrollpaint +}; + +void window_tile_inspector_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_class(WC_TILE_INSPECTOR); + if (window != NULL) + return; + + window = window_create( + 0, + 29, + WW, + WH, + (uint32*)window_tile_inspector_events, + WC_TILE_INSPECTOR, + WF_RESIZABLE + ); + window->widgets = window_tile_inspector_widgets; + window->enabled_widgets = (1 << WIDX_CLOSE); + + window_init_scroll_widgets(window); + window->colours[0] = 7; + window->colours[1] = 7; + window->colours[2] = 7; + window->min_width = WW; + window->min_height = MIN_WH; + window->max_width = WW; + window->max_height = MAX_WH; + + window_tile_inspector_tile_x = -1; + window_tile_inspector_tile_y = -1; + + tool_set(window, WIDX_BACKGROUND, 12); +} + +static void window_tile_inspector_close() +{ + tool_cancel(); +} + +static void window_tile_inspector_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + } +} + +static void window_tile_inspector_resize() +{ + rct_window *w; + + window_get_register(w); + + w->min_width = WW; + w->min_height = MIN_WH; + if (w->width < w->min_width) { + window_invalidate(w); + w->width = w->min_width; + } + if (w->height < w->min_height) { + window_invalidate(w); + w->height = w->min_height; + } +} + +static void window_tile_inspector_tool_update() +{ + short widgetIndex; + rct_window *w; + short x, y; + int direction; + + window_tool_get_registers(w, widgetIndex, x, y); + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + screen_pos_to_map_pos(&x, &y, &direction); + + if (x == (short)0x8000) { + return; + } + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + + map_invalidate_selection_rect(); + +} + +static void window_tile_inspector_tool_down() +{ + short widgetIndex; + rct_window* w; + short x, y; + int direction; + + window_tool_get_registers(w, widgetIndex, x, y); + screen_pos_to_map_pos(&x, &y, &direction); + + if (x == (short)0x8000) { + return; + } + + window_tile_inspector_tile_x = x >> 5; + window_tile_inspector_tile_y = y >> 5; + + rct_map_element *element = map_get_first_element_at(window_tile_inspector_tile_x, window_tile_inspector_tile_y); + int numItems = 0; + do { + numItems++; + } while (!map_element_is_last_for_tile(element++)); + + window_tile_inspector_item_count = numItems; + + w->scrolls[0].v_top = 0; + window_invalidate(w); +} + +static void window_tile_inspector_tool_abort() +{ + rct_window *w; + short widgetIndex, x, y; + window_tool_get_registers(w, widgetIndex, x, y); + window_close(w); +} + +static void window_tile_inspector_scrollgetsize() +{ + + rct_window *w; + int width, height; + window_get_register(w); + + height = window_tile_inspector_item_count * 11; + width = WW - 30; + + window_scrollsize_set_registers(width, height); + +} + +static void window_tile_inspector_scrollmouseover() +{ + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + window_invalidate(w); +} + +static void window_tile_inspector_invalidate() +{ + rct_window *w; + + window_get_register(w); + + window_tile_inspector_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_tile_inspector_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + window_tile_inspector_widgets[WIDX_CLOSE].left = w->width - 13; + window_tile_inspector_widgets[WIDX_CLOSE].right = w->width - 3; + window_tile_inspector_widgets[WIDX_CONTENT_PANEL].right = w->width - 1; + window_tile_inspector_widgets[WIDX_CONTENT_PANEL].bottom = w->height - 1; + window_tile_inspector_widgets[WIDX_SCROLL].bottom = w->height - 30; +} + +static void window_tile_inspector_paint() +{ + int x, y; + rct_window *w; + rct_drawpixelinfo *dpi; + char buffer[256]; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + x = w->x + 20; + y = w->y + 25; + + if (window_tile_inspector_tile_x == -1) { + + // No tile selected + gfx_draw_string_left(dpi, STR_TILE_INSPECTOR_CHOOSE_MSG, NULL, 12, x, y); + + } else { + + sprintf( + buffer, + "X: %d, Y: %d", + window_tile_inspector_tile_x, + window_tile_inspector_tile_y + ); + + gfx_draw_string(dpi, buffer, 12, x, y); + + } + + y += 25; + + draw_string_left_underline(dpi, STR_TILE_INSPECTOR_ELEMENT_TYPE, NULL, 12, x, y); + draw_string_left_underline(dpi, STR_TILE_INSPECTOR_BASE_HEIGHT, NULL, 12, x + 200, y); + draw_string_left_underline(dpi, STR_TILE_INSPECTOR_CLEARANGE_HEIGHT, NULL, 12, x + 280, y); + draw_string_left_underline(dpi, STR_TILE_INSPECTOR_FLAGS, NULL, 12, x + 390, y); + +} + +static void window_tile_inspector_scrollpaint() +{ + int x = 15, y = 11 * (window_tile_inspector_item_count - 1), i = 0; + rct_window *w; + rct_drawpixelinfo *dpi; + char buffer[256]; + + window_paint_get_registers(w, dpi); + + if (window_tile_inspector_tile_x == -1) + return; + + rct_map_element *element = map_get_first_element_at(window_tile_inspector_tile_x, window_tile_inspector_tile_y); + + do { + + int type = map_element_get_type(element); + char *type_name; + int base_height = element->base_height; + int clearance_height = element->clearance_height; + + if ((i & 1) != 0) + gfx_fill_rect(dpi, x - 15, y, x + WW - 20, y + 11, RCT2_GLOBAL(0x0141FC4A + (w->colours[1] * 8), uint8) | 0x1000000); + + switch (type) { + case MAP_ELEMENT_TYPE_SURFACE: + sprintf( + buffer, + "Surface (%s, %s)", + language_get_string(STR_TILE_INSPECTOR_TERRAIN_START + map_element_get_terrain(element)), + language_get_string(STR_TILE_INSPECTOR_TERRAIN_EDGE_START + map_element_get_terrain_edge(element)) + ); + type_name = buffer; + break; + case MAP_ELEMENT_TYPE_PATH: + { + // TODO: use these + uint8 pathType, pathDirection; + pathType = element->properties.path.type >> 2; + pathDirection = element->properties.path.type & 3; + } + sprintf( + buffer, + "Path (%s)", + "" // TODO: queue? has bins? has benches? e.t.c. + ); + type_name = buffer; + break; + case MAP_ELEMENT_TYPE_TRACK: + type_name = "Track"; // TODO: show type? + break; + case MAP_ELEMENT_TYPE_SCENERY: + sprintf( + buffer, + "Scenery (%s)", + language_get_string(g_smallSceneryEntries[element->properties.scenery.type]->name) + ); + type_name = buffer; + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + sprintf( + buffer, + "Entrance (%s)", + language_get_string(STR_TILE_INSPECTOR_ENTRANCE_START + element->properties.entrance.type) + ); + type_name = buffer; + break; + case MAP_ELEMENT_TYPE_FENCE: + sprintf( + buffer, + "Fence (%s)", + language_get_string(g_wallSceneryEntries[element->properties.scenery.type]->name) + ); + type_name = buffer; + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + type_name = "Scenery multiple"; + break; + case MAP_ELEMENT_TYPE_BANNER: + sprintf( + buffer, + "Banner (%d)", + element->properties.banner.index + ); + type_name = buffer; + break; + } + + gfx_draw_string(dpi, type_name, 12, x, y); + gfx_draw_string_left(dpi, 5182, &base_height, 12, x + 200, y); + gfx_draw_string_left(dpi, 5182, &clearance_height, 12, x + 280, y); + + uint8 flags = element->flags; + char j; + + buffer[8] = '\0'; + + for (j = 7; j >= 0; j--, flags >>= 1) { + buffer[j] = flags & 1 ? '1' : '0'; + } + + gfx_draw_string(dpi, buffer, 12, x + 390, y); + + y -= 11; + i++; + + } while (!map_element_is_last_for_tile(element++)); + +} diff --git a/src/windows/title_exit.c b/src/windows/title_exit.c index 2e8478f5fb..37ea4942fd 100644 --- a/src/windows/title_exit.c +++ b/src/windows/title_exit.c @@ -19,11 +19,13 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../game.h" #include "../sprites.h" #include "../localisation/localisation.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../interface/themes.h" static rct_widget window_title_exit_widgets[] = { { WWT_IMGBTN, 2, 0, 39, 0, 63, SPR_MENU_EXIT, STR_EXIT }, @@ -33,6 +35,7 @@ static rct_widget window_title_exit_widgets[] = { static void window_title_exit_emptysub() {} static void window_title_exit_paint(); static void window_title_exit_mouseup(); +static void window_title_exit_invalidate(); static void* window_title_exit_events[] = { window_title_exit_emptysub, @@ -60,7 +63,7 @@ static void* window_title_exit_events[] = { window_title_exit_emptysub, window_title_exit_emptysub, window_title_exit_emptysub, - window_title_exit_emptysub, + window_title_exit_invalidate, window_title_exit_paint, window_title_exit_emptysub }; @@ -78,15 +81,11 @@ void window_title_exit_open() 40, 64, (uint32*)window_title_exit_events, WC_TITLE_EXIT, - WF_STICK_TO_FRONT + WF_STICK_TO_BACK | WF_TRANSPARENT ); window->widgets = window_title_exit_widgets; window->enabled_widgets |= 1; window_init_scroll_widgets(window); - window->flags |= 16; - window->colours[0] = 140; - window->colours[1] = 140; - window->colours[2] = 140; } /** @@ -120,4 +119,11 @@ static void window_title_exit_paint() window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); -} \ No newline at end of file +} + +static void window_title_exit_invalidate() +{ + rct_window *w; + window_get_register(w); + colour_scheme_update(w); +} diff --git a/src/windows/title_logo.c b/src/windows/title_logo.c index 835ab23d67..dbb473c4bf 100644 --- a/src/windows/title_logo.c +++ b/src/windows/title_logo.c @@ -63,6 +63,8 @@ static void* window_title_logo_events[] = { window_title_logo_emptysub }; +static void window_title_logo_draw_expansion_packs(rct_drawpixelinfo *dpi); + /** * Creates the window containing the logo and the expansion packs on the title screen. * rct2: 0x0066B679 (part of 0x0066B3E8) @@ -79,10 +81,17 @@ void window_title_logo_open() packs++; // Create the window - window = window_create(0, 0, 200, 106 + (10 * packs), (uint32*)window_title_logo_events, WC_TITLE_LOGO, WF_STICK_TO_FRONT); + window = window_create( + 0, + 0, + 200, + 106 + (10 * packs), + (uint32*)window_title_logo_events, + WC_TITLE_LOGO, + WF_STICK_TO_BACK | WF_TRANSPARENT + ); window->widgets = (rct_widget*)0x009A9658; // mouse move bug in original game, keep this address and no crash happens window_init_scroll_widgets(window); - window->flags |= 16; window->colours[0] = 129; window->colours[1] = 129; window->colours[2] = 129; @@ -94,23 +103,29 @@ void window_title_logo_open() */ static void window_title_logo_paint() { - int packs, x, y, i; - char *buffer, *names; rct_window *w; rct_drawpixelinfo *dpi; window_paint_get_registers(w, dpi); - gfx_draw_sprite(dpi, SPR_MENU_LOGO, w->x, w->y, 0); + // gfx_draw_sprite(dpi, SPR_MENU_LOGO, w->x, w->y, 0); + int x = 2, y = 2; + gfx_draw_sprite(dpi, SPR_G2_LOGO, w->x + x, w->y + y, 0); + gfx_draw_sprite(dpi, SPR_G2_TITLE, w->x + x + 104, w->y + y + 18, 0); + window_title_logo_draw_expansion_packs(dpi); +} + +static void window_title_logo_draw_expansion_packs(rct_drawpixelinfo *dpi) +{ + int packs, x, y, i; + char *buffer, *names; x = 0; y = 105; packs = RCT2_GLOBAL(RCT2_ADDRESS_EXPANSION_FLAGS, uint16); names = RCT2_ADDRESS(RCT2_ADDRESS_EXPANSION_NAMES, char); - buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; - while (packs != 0) { if (packs & 1) { // Prefix for expansion name @@ -120,23 +135,19 @@ static void window_title_logo_paint() buffer[3] = '+'; buffer[4] = ' '; - i = 0; - // Copies the expansion name to the buffer, offset by 5 + i = 0; do { buffer[5 + i] = names[i]; i++; } while (names[i - 1] != 0); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint32) = 0; - gfx_draw_string(dpi, buffer, 0, x, y); - y += 10; } packs = packs >> 1; - names += 128; } } \ No newline at end of file diff --git a/src/windows/title_menu.c b/src/windows/title_menu.c index 88bf10d8f5..fc65c97a2c 100644 --- a/src/windows/title_menu.c +++ b/src/windows/title_menu.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../editor.h" #include "../game.h" #include "../interface/widget.h" @@ -27,6 +28,7 @@ #include "../sprites.h" #include "../tutorial.h" #include "dropdown.h" +#include "../interface/themes.h" enum { WIDX_START_NEW_GAME, @@ -49,6 +51,7 @@ static void window_title_menu_mousedown(int widgetIndex, rct_window*w, rct_widge static void window_title_menu_dropdown(); static void window_title_menu_unknown17(); static void window_title_menu_paint(); +static void window_title_menu_invalidate(); static void* window_title_menu_events[] = { window_title_menu_emptysub, @@ -76,7 +79,7 @@ static void* window_title_menu_events[] = { window_title_menu_emptysub, window_title_menu_unknown17, window_title_menu_emptysub, - window_title_menu_emptysub, + window_title_menu_invalidate, window_title_menu_paint, window_title_menu_emptysub }; @@ -94,15 +97,11 @@ void window_title_menu_open() 328, 82, (uint32*)window_title_menu_events, WC_TITLE_MENU, - WF_STICK_TO_FRONT + WF_STICK_TO_BACK | WF_TRANSPARENT ); window->widgets = window_title_menu_widgets; window->enabled_widgets |= (8 | 4 | 2 | 1); window_init_scroll_widgets(window); - window->flags |= 16; - window->colours[0] = 140; - window->colours[1] = 140; - window->colours[2] = 140; } static void window_title_menu_mouseup() @@ -130,7 +129,7 @@ static void window_title_menu_mousedown(int widgetIndex, rct_window*w, rct_widge w->y + widget->top, widget->bottom - widget->top + 1, w->colours[0] | 0x80, - 0x80, + DROPDOWN_FLAG_STAY_OPEN, 3 ); } else if (widgetIndex == WIDX_GAME_TOOLS) { @@ -143,7 +142,7 @@ static void window_title_menu_mousedown(int widgetIndex, rct_window*w, rct_widge w->y + widget->top, widget->bottom - widget->top + 1, w->colours[0] | 0x80, - 0x80, + DROPDOWN_FLAG_STAY_OPEN, 4 ); } @@ -190,3 +189,10 @@ static void window_title_menu_paint() window_draw_widgets(w, dpi); } + +static void window_title_menu_invalidate() +{ + rct_window *w; + window_get_register(w); + colour_scheme_update(w); +} diff --git a/src/windows/title_options.c b/src/windows/title_options.c new file mode 100644 index 0000000000..39be909cbd --- /dev/null +++ b/src/windows/title_options.c @@ -0,0 +1,118 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John, Timmy Weerwag + * 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 "../config.h" +#include "../game.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../interface/themes.h" + +static rct_widget window_title_options_widgets[] = { + { WWT_DROPDOWN_BUTTON, 2, 0, 79, 0, 11, STR_OPTIONS, STR_NONE }, + { WIDGETS_END }, +}; + +static void window_title_options_emptysub() {} +static void window_title_options_paint(); +static void window_title_options_mouseup(); +static void window_title_options_invalidate(); + +static void* window_title_options_events[] = { + window_title_options_emptysub, + window_title_options_mouseup, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_emptysub, + window_title_options_invalidate, + window_title_options_paint, + window_title_options_emptysub +}; + +/** + * Creates the window containing the options button on the title screen. + */ +void window_title_options_open() +{ + rct_window* window; + + window = window_create( + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 80, 0, + 80, 12, + (uint32*)window_title_options_events, + WC_TITLE_OPTIONS, + WF_STICK_TO_BACK | WF_TRANSPARENT + ); + window->widgets = window_title_options_widgets; + window->enabled_widgets |= 1; + window_init_scroll_widgets(window); +} + +static void window_title_options_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + if (RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) != 0) + return; + + if (widgetIndex == 0) + window_options_open(); +} + +static void window_title_options_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); +} + +static void window_title_options_invalidate() +{ + rct_window *w; + window_get_register(w); + colour_scheme_update(w); +} diff --git a/src/windows/title_scenarioselect.c b/src/windows/title_scenarioselect.c index acc362dc7d..8fdf3fc80c 100644 --- a/src/windows/title_scenarioselect.c +++ b/src/windows/title_scenarioselect.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../config.h" #include "../audio/audio.h" #include "../localisation/date.h" #include "../localisation/localisation.h" @@ -26,6 +27,7 @@ #include "../sprites.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../interface/themes.h" enum { WIDX_BACKGROUND, @@ -111,22 +113,17 @@ void window_scenarioselect_open() // Load scenario list scenario_load_list(); - window = window_create( - (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2) - 305, - max(28, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) / 2) - 167), + window = window_create_centred( 610, 334, (uint32*)window_scenarioselect_events, WC_SCENARIO_SELECT, - WF_STICK_TO_FRONT | WF_10 + WF_10 ); window->widgets = window_scenarioselect_widgets; window->enabled_widgets = 0x04 | 0x10 | 0x20 | 0x40 | 0x80 | 0x100; window_init_scroll_widgets(window); - window->colours[0] = 1; - window->colours[1] = 26; - window->colours[2] = 26; window->viewport_focus_coordinates.var_480 = -1; window->var_494 = 0; @@ -184,8 +181,8 @@ static void window_scenarioselect_mousedown(int widgetIndex, rct_window*w, rct_w w->selected_tab = widgetIndex - 4; w->var_494 = 0; window_invalidate(w); - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + window_event_resize_call(w); + window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); } @@ -193,12 +190,13 @@ static void window_scenarioselect_mousedown(int widgetIndex, rct_window*w, rct_w static void window_scenarioselect_scrollgetsize() { - int i, height; + int i, width, height; rct_window *w; rct_scenario_basic *scenario; window_get_register(w); + width = 0; height = 0; for (i = 0; i < gScenarioListCount; i++) { scenario = &gScenarioList[i]; @@ -208,29 +206,18 @@ static void window_scenarioselect_scrollgetsize() height += 24; } - #ifdef _MSC_VER - __asm mov ecx, 0 - #else - __asm__ ( "mov ecx, 0 " ); - #endif - - #ifdef _MSC_VER - __asm mov edx, height - #else - __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); - #endif - + window_scrollsize_set_registers(width, height); } /* rct2: 0x6780FE */ static void window_scenarioselect_scrollmousedown() { int i; - short x, y; + short x, y, scrollIndex; rct_window *w; rct_scenario_basic *scenario; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); for (i = 0; i < gScenarioListCount; i++) { scenario = &gScenarioList[i]; @@ -253,11 +240,11 @@ static void window_scenarioselect_scrollmousedown() static void window_scenarioselect_scrollmouseover() { int i; - short x, y; + short x, y, scrollIndex; rct_window *w; rct_scenario_basic *scenario, *selected; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); selected = NULL; for (i = 0; i < gScenarioListCount; i++) { @@ -285,6 +272,7 @@ static void window_scenarioselect_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); w->pressed_widgets &= ~(0x10 | 0x20 | 0x40 | 0x80 | 0x100); w->pressed_widgets |= 1LL << (w->selected_tab + 4); @@ -292,7 +280,7 @@ static void window_scenarioselect_invalidate() static void window_scenarioselect_paint() { - int i, x, y; + int i, x, y, format; rct_window *w; rct_drawpixelinfo *dpi; rct_widget *widget; @@ -301,6 +289,8 @@ static void window_scenarioselect_paint() window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); + + format = (theme_get_preset()->features.rct1_scenario_font) ? 5138 : 1193; // Text for each tab for (i = 0; i < 5; i++) { @@ -311,7 +301,7 @@ static void window_scenarioselect_paint() x = (widget->left + widget->right) / 2 + w->x; y = (widget->top + widget->bottom) / 2 + w->y - 3; RCT2_GLOBAL(0x013CE952 + 0, short) = STR_BEGINNER_PARKS + i; - gfx_draw_string_centred_wrapped(dpi, (void*)0x013CE952, x, y, 87, 1193, 10); + gfx_draw_string_centred_wrapped(dpi, (void*)0x013CE952, x, y, 87, format, 10); } // Return if no scenario highlighted @@ -354,7 +344,7 @@ static void window_scenarioselect_paint() static void window_scenarioselect_scrollpaint() { - int i, y, colour, highlighted; + int i, y, colour, highlighted, highlighted_format, unhighlighted_format; rct_window *w; rct_drawpixelinfo *dpi; rct_scenario_basic *scenario; @@ -365,6 +355,9 @@ static void window_scenarioselect_scrollpaint() colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; gfx_clear(dpi, colour); + highlighted_format = (theme_get_preset()->features.rct1_scenario_font) ? 5139 : 1193; + unhighlighted_format = (theme_get_preset()->features.rct1_scenario_font) ? 5139 : 1191; + y = 0; for (i = 0; i < gScenarioListCount; i++) { scenario = &gScenarioList[i]; @@ -385,7 +378,7 @@ static void window_scenarioselect_scrollpaint() // Draw scenario name strcpy((char*)0x009BC677, scenario->name); RCT2_GLOBAL(0x013CE952, short) = 3165; - gfx_draw_string_centred(dpi, highlighted ? 1193 : 1191, 210, y + 1, 0, (void*)0x013CE952); + gfx_draw_string_centred(dpi, highlighted ? highlighted_format : unhighlighted_format, 210, y + 1, 0, (void*)0x013CE952); // Check if scenario is completed if (scenario->flags & SCENARIO_FLAGS_COMPLETED) { diff --git a/src/windows/tooltip.c b/src/windows/tooltip.c index 507e9db2f3..8a6e8a11e2 100644 --- a/src/windows/tooltip.c +++ b/src/windows/tooltip.c @@ -79,7 +79,7 @@ void window_tooltip_reset(int x, int y) RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(1 << 4); } -extern uint8* gTooltip_text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_TOOLTIP_TEXT_BUFFER, uint8); +uint8* gTooltip_text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_TOOLTIP_TEXT_BUFFER, uint8); /** * * rct2: 0x006EA10D @@ -94,7 +94,7 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y return; widget = &widgetWindow->widgets[widgetIndex]; - RCT2_CALLPROC_X(widgetWindow->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)widgetWindow, 0, 0); + window_event_invalidate_call(widgetWindow); if (widget->tooltip == 0xFFFF) return; @@ -102,11 +102,7 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = widgetWindow->number; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = widgetIndex; - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = widgetIndex; - esi = (int)widgetWindow; - RCT2_CALLFUNC_X(widgetWindow->event_handlers[WE_TOOLTIP], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if ((eax & 0xFFFF) == 0xFFFF) + if (window_event_tooltip_call(widgetWindow, widgetIndex) == (rct_string_id)STR_NONE) return; w = window_find_by_class(WC_ERROR); @@ -128,7 +124,9 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y tooltip_text_width = 196; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - tooltip_text_width = gfx_wrap_string(buffer, tooltip_text_width + 1, &tooltip_text_height, &ebx); + + int fontHeight; + tooltip_text_width = gfx_wrap_string(buffer, tooltip_text_width + 1, &tooltip_text_height, &fontHeight); RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, sint16) = tooltip_text_height; width = tooltip_text_width + 3; @@ -139,9 +137,24 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y memcpy(gTooltip_text_buffer, buffer, 512); x = clamp(0, x - (width / 2), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width); - y = clamp(22, y + 26, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height - 40); - w = window_create(x, y, width, height, (uint32*)window_tooltip_events, WC_TOOLTIP, WF_TRANSPARENT | WF_STICK_TO_FRONT); + int max_y = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height; + y += 26; // Normally, we'd display the tooltip 26 lower + if (y > max_y) + // If y is too large, the tooltip could be forced below the cursor if we'd just clamped y, + // so we'll subtract a bit more + y -= height + 40; + y = clamp(22, y, max_y); + + w = window_create( + x, + y, + width, + height, + (uint32*)window_tooltip_events, + WC_TOOLTIP, + WF_TRANSPARENT | WF_STICK_TO_FRONT + ); w->widgets = window_tooltip_widgets; RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) = 0; diff --git a/src/windows/top_toolbar.c b/src/windows/top_toolbar.c new file mode 100644 index 0000000000..7079828796 --- /dev/null +++ b/src/windows/top_toolbar.c @@ -0,0 +1,2983 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#include "../addresses.h" +#include "../config.h" +#include "../editor.h" +#include "../game.h" +#include "../input.h" +#include "../sprites.h" +#include "../audio/audio.h" +#include "../interface/screenshot.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../interface/viewport.h" +#include "../localisation/localisation.h" +#include "../network/twitch.h" +#include "../scenario.h" +#include "../world/scenery.h" +#include "../world/banner.h" +#include "dropdown.h" +#include "../interface/themes.h" +#include "../interface/console.h" + +enum { + WIDX_PAUSE, + WIDX_FILE_MENU, + WIDX_ZOOM_OUT, + WIDX_ZOOM_IN, + WIDX_ROTATE, + WIDX_VIEW_MENU, + WIDX_MAP, + + WIDX_LAND, + WIDX_WATER, + WIDX_SCENERY, + WIDX_PATH, + WIDX_CONSTRUCT_RIDE, + WIDX_RIDES, + WIDX_PARK, + WIDX_STAFF, + WIDX_GUESTS, + WIDX_CLEAR_SCENERY, + + WIDX_FASTFORWARD, + WIDX_CHEATS, + WIDX_DEBUG, + WIDX_FINANCES, + WIDX_RESEARCH, + + WIDX_SEPARATOR, +}; + +typedef enum { + DDIDX_LOAD_GAME = 0, + DDIDX_SAVE_GAME = 1, + // seperator + DDIDX_ABOUT = 3, + DDIDX_OPTIONS = 4, + DDIDX_SCREENSHOT = 5, + DDIDX_GIANT_SCREENSHOT = 6, + // seperator + DDIDX_QUIT_TO_MENU = 8, + DDIDX_EXIT_OPENRCT2 = 9, + // seperator + DDIDX_ENABLE_TWITCH = 11 +} FILE_MENU_DDIDX; + +typedef enum { + DDIDX_UNDERGROUND_INSIDE = 0, + DDIDX_HIDE_BASE = 1, + DDIDX_HIDE_VERTICAL = 2, + DDIDX_SEETHROUGH_RIDES = 4, + DDIDX_SEETHROUGH_SCENARY = 5, + DDIDX_INVISIBLE_SUPPORTS = 6, + DDIDX_INVISIBLE_PEEPS = 7, + DDIDX_LAND_HEIGHTS = 9, + DDIDX_TRACK_HEIGHTS = 10, + DDIDX_PATH_HEIGHTS = 11, +} TOP_TOOLBAR_VIEW_MENU_DDIDX; + +typedef enum { + DDIDX_CONSOLE = 0, + DDIDX_TILE_INSPECTOR = 1 +} TOP_TOOLBAR_DEBUG_DDIDX; + +#pragma region Toolbar_widget_ordering + +// from left to right +static const int left_aligned_widgets_order[] = { + WIDX_PAUSE, + WIDX_FASTFORWARD, + WIDX_FILE_MENU, + WIDX_CHEATS, + WIDX_DEBUG, + + WIDX_SEPARATOR, + + WIDX_ZOOM_OUT, + WIDX_ZOOM_IN, + WIDX_ROTATE, + WIDX_VIEW_MENU, + WIDX_MAP, +}; + +// from right to left +static const int right_aligned_widgets_order[] = { + WIDX_GUESTS, + WIDX_STAFF, + WIDX_PARK, + WIDX_RIDES, + WIDX_RESEARCH, + WIDX_FINANCES, + + WIDX_SEPARATOR, + + WIDX_CONSTRUCT_RIDE, + WIDX_PATH, + WIDX_SCENERY, + WIDX_WATER, + WIDX_LAND, + WIDX_CLEAR_SCENERY, +}; + +#pragma endregion + +static rct_widget window_top_toolbar_widgets[] = { + { WWT_TRNBTN, 0, 0x0000, 0x001D, 0, 27, 0x20000000 | SPR_TOOLBAR_PAUSE, STR_PAUSE_GAME_TIP }, // Pause + { WWT_TRNBTN, 0, 0x001E + 30, 0x003B + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_FILE, STR_DISC_AND_GAME_OPTIONS_TIP }, // File menu + { WWT_TRNBTN, 1, 0x0046 + 30, 0x0063 + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_ZOOM_OUT, STR_ZOOM_OUT_TIP }, // Zoom out + { WWT_TRNBTN, 1, 0x0064 + 30, 0x0081 + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_ZOOM_IN, STR_ZOOM_IN_TIP }, // Zoom in + { WWT_TRNBTN, 1, 0x0082 + 30, 0x009F + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_ROTATE, STR_ROTATE_TIP }, // Rotate camera + { WWT_TRNBTN, 1, 0x00A0 + 30, 0x00BD + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_VIEW, STR_VIEW_OPTIONS_TIP }, // Transparancy menu + { WWT_TRNBTN, 1, 0x00BE + 30, 0x00DB + 30, 0, 27, 0x20000000 | SPR_TOOLBAR_MAP, STR_SHOW_MAP_TIP }, // Map + + { WWT_TRNBTN, 2, 0x010B, 0x0128, 0, 27, 0x20000000 | SPR_TOOLBAR_LAND, STR_ADJUST_LAND_TIP }, // Land + { WWT_TRNBTN, 2, 0x0129, 0x0146, 0, 27, 0x20000000 | SPR_TOOLBAR_WATER, STR_ADJUST_WATER_TIP }, // Water + { WWT_TRNBTN, 2, 0x0147, 0x0164, 0, 27, 0x20000000 | SPR_TOOLBAR_SCENERY, STR_PLACE_SCENERY_TIP }, // Scenery + { WWT_TRNBTN, 2, 0x0165, 0x0182, 0, 27, 0x20000000 | SPR_TOOLBAR_FOOTPATH, STR_BUILD_FOOTPATH_TIP }, // Path + { WWT_TRNBTN, 2, 0x0183, 0x01A0, 0, 27, 0x20000000 | SPR_TOOLBAR_CONSTRUCT_RIDE, STR_BUILD_RIDE_TIP }, // Construct ride + { WWT_TRNBTN, 3, 0x01EA, 0x0207, 0, 27, 0x20000000 | SPR_TOOLBAR_RIDES, STR_RIDES_IN_PARK_TIP }, // Rides + { WWT_TRNBTN, 3, 0x0208, 0x0225, 0, 27, 0x20000000 | SPR_TOOLBAR_PARK, STR_PARK_INFORMATION_TIP }, // Park + { WWT_TRNBTN, 3, 0x0226, 0x0243, 0, 27, 0x20000000 | 0x15F9, STR_STAFF_TIP }, // Staff + { WWT_TRNBTN, 3, 0x0230, 0x024D, 0, 27, 0x20000000 | SPR_TOOLBAR_GUESTS, STR_GUESTS_TIP }, // Guests + { WWT_TRNBTN, 2, 0x0230, 0x024D, 0, 27, 0x20000000 | SPR_TOOLBAR_CLEAR_SCENERY, STR_CLEAR_SCENERY_TIP }, // Clear scenery + + { WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, 5148 }, // Fast forward + { WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, 5149 }, // Cheats + { WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_DEBUG_TIP }, // Debug + { WWT_TRNBTN, 3, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, 3235 }, // Finances + { WWT_TRNBTN, 3, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, 2275 }, // Research + + { WWT_EMPTY, 0, 0, 10-1, 0, 0, 0xFFFFFFFF, STR_NONE }, // Artificial widget separator + { WIDGETS_END }, +}; + +static void window_top_toolbar_emptysub() { } +static void window_top_toolbar_mouseup(); +static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_top_toolbar_dropdown(); +static void window_top_toolbar_tool_update(); +static void window_top_toolbar_tool_down(); +static void window_top_toolbar_tool_drag(); +static void window_top_toolbar_invalidate(); +static void window_top_toolbar_paint(); + +static void* window_top_toolbar_events[] = { + window_top_toolbar_emptysub, + window_top_toolbar_mouseup, + window_top_toolbar_emptysub, + window_top_toolbar_mousedown, + window_top_toolbar_dropdown, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, // check if editor versions are significantly different... + window_top_toolbar_tool_update, // editor: 0x0066fB0E + window_top_toolbar_tool_down, // editor: 0x0066fB5C + window_top_toolbar_tool_drag, // editor: 0x0066fB37 + (void*)0x0066CC5B, // editor: 0x0066fC44 + (void*)0x0066CA58, // editor: 0x0066fA74 + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_emptysub, + window_top_toolbar_invalidate, + window_top_toolbar_paint, + window_top_toolbar_emptysub +}; + +void top_toolbar_init_view_menu(rct_window *window, rct_widget *widget); +void top_toolbar_view_menu_dropdown(short dropdownIndex); +void top_toolbar_init_fastforward_menu(rct_window *window, rct_widget *widget); +void top_toolbar_fastforward_menu_dropdown(short dropdownIndex); +void top_toolbar_init_debug_menu(rct_window *window, rct_widget *widget); +void top_toolbar_debug_menu_dropdown(short dropdownIndex); + +void toggle_footpath_window(); +void toggle_land_window(rct_window *topToolbar, int widgetIndex); +void toggle_clear_scenery_window(rct_window *topToolbar, int widgetIndex); +void toggle_water_window(rct_window *topToolbar, int widgetIndex); + +money32 selection_lower_land(uint8 flags); +money32 selection_raise_land(uint8 flags); + +static bool _menuDropdownIncludesTwitch; + +/** + * Creates the main game top toolbar window. + * rct2: 0x0066B485 (part of 0x0066B3E8) + */ +void window_top_toolbar_open() +{ + rct_window* window; + + window = window_create( + 0, 0, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), 28, + (uint32*)window_top_toolbar_events, + WC_TOP_TOOLBAR, + WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5 + ); + window->widgets = window_top_toolbar_widgets; + + window_init_scroll_widgets(window); +} + +/** + * + * rct2: 0x0066C957 + */ +static void window_top_toolbar_mouseup() +{ + short widgetIndex; + rct_window *w, *mainWindow; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_PAUSE: + game_do_command(0, 1, 0, 0, GAME_COMMAND_TOGGLE_PAUSE, 0, 0); + break; + case WIDX_ZOOM_OUT: + if ((mainWindow = window_get_main()) != NULL) + window_zoom_out(mainWindow); + break; + case WIDX_ZOOM_IN: + if ((mainWindow = window_get_main()) != NULL) + window_zoom_in(mainWindow); + break; + case WIDX_ROTATE: + if ((mainWindow = window_get_main()) != NULL) + window_rotate_camera(mainWindow); + break; + case WIDX_CLEAR_SCENERY: + toggle_clear_scenery_window(w, WIDX_CLEAR_SCENERY); + break; + case WIDX_LAND: + toggle_land_window(w, WIDX_LAND); + break; + case WIDX_WATER: + toggle_water_window(w, WIDX_WATER); + break; + case WIDX_SCENERY: + if (!tool_set(w, WIDX_SCENERY, 0)) { + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + window_scenery_open(); + } + break; + case WIDX_PATH: + toggle_footpath_window(); + break; + case WIDX_CONSTRUCT_RIDE: + window_new_ride_open(); + break; + case WIDX_RIDES: + window_ride_list_open(); + break; + case WIDX_PARK: + window_park_entrance_open(); + break; + case WIDX_STAFF: + window_staff_list_open(); + break; + case WIDX_GUESTS: + window_guest_list_open(); + break; + case WIDX_FINANCES: + window_finances_open(); + break; + case WIDX_RESEARCH: + window_research_open(); + break; + case WIDX_CHEATS: + window_cheats_open(); + break; + } +} + +/** + * + * rct2: 0x0066CA3B + */ +static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) +{ + int numItems; + + switch (widgetIndex) { + case WIDX_FILE_MENU: + _menuDropdownIncludesTwitch = false; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { + gDropdownItemsFormat[0] = STR_ABOUT; + gDropdownItemsFormat[1] = STR_OPTIONS; + gDropdownItemsFormat[2] = STR_SCREENSHOT; + gDropdownItemsFormat[3] = STR_GIANT_SCREENSHOT; + gDropdownItemsFormat[4] = 0; + gDropdownItemsFormat[5] = STR_QUIT_TRACK_DESIGNS_MANAGER; + gDropdownItemsFormat[6] = STR_EXIT_OPENRCT2; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) + gDropdownItemsFormat[5] = STR_QUIT_ROLLERCOASTER_DESIGNER; + + numItems = 7; + } else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) { + gDropdownItemsFormat[0] = STR_LOAD_LANDSCAPE; + gDropdownItemsFormat[1] = STR_SAVE_LANDSCAPE; + gDropdownItemsFormat[2] = 0; + gDropdownItemsFormat[3] = STR_ABOUT; + gDropdownItemsFormat[4] = STR_OPTIONS; + gDropdownItemsFormat[5] = STR_SCREENSHOT; + gDropdownItemsFormat[6] = STR_GIANT_SCREENSHOT; + gDropdownItemsFormat[7] = 0; + gDropdownItemsFormat[8] = STR_QUIT_SCENARIO_EDITOR; + gDropdownItemsFormat[9] = STR_EXIT_OPENRCT2; + numItems = 10; + } else { + gDropdownItemsFormat[0] = STR_LOAD_GAME; + gDropdownItemsFormat[1] = STR_SAVE_GAME; + gDropdownItemsFormat[2] = 0; + gDropdownItemsFormat[3] = STR_ABOUT; + gDropdownItemsFormat[4] = STR_OPTIONS; + gDropdownItemsFormat[5] = STR_SCREENSHOT; + gDropdownItemsFormat[6] = STR_GIANT_SCREENSHOT; + gDropdownItemsFormat[7] = 0; + gDropdownItemsFormat[8] = STR_QUIT_TO_MENU; + gDropdownItemsFormat[9] = STR_EXIT_OPENRCT2; + numItems = 10; + + #ifndef DISABLE_TWITCH + if (gConfigTwitch.channel != NULL && gConfigTwitch.channel[0] != 0) { + _menuDropdownIncludesTwitch = true; + gDropdownItemsFormat[10] = 0; + gDropdownItemsFormat[11] = 1156; + gDropdownItemsArgs[11] = STR_TWITCH_ENABLE; + numItems = 12; + } + #endif + } + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[0] | 0x80, + DROPDOWN_FLAG_STAY_OPEN, + numItems + ); + +#ifndef DISABLE_TWITCH + if (_menuDropdownIncludesTwitch && gTwitchEnable) + gDropdownItemsChecked |= (1 << 11); +#endif + break; + case WIDX_VIEW_MENU: + top_toolbar_init_view_menu(w, widget); + break; + case WIDX_MAP: + gDropdownItemsFormat[0] = 2523; + gDropdownItemsFormat[1] = 2780; + numItems = 2; + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && g_editor_step == EDITOR_STEP_LANDSCAPE_EDITOR) { + gDropdownItemsFormat[2] = 2690; + numItems++; + } + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1] | 0x80, + 0, + numItems + ); + RCT2_GLOBAL(0x009DEBA2, uint16) = 0; + break; + case WIDX_FASTFORWARD: + top_toolbar_init_fastforward_menu(w, widget); + break; + case WIDX_DEBUG: + top_toolbar_init_debug_menu(w, widget); + break; + } +} + +/** + * + * rct2: 0x0066C9EA + */ +static void window_top_toolbar_dropdown() +{ + short widgetIndex, dropdownIndex; + rct_window* w; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + switch (widgetIndex) { + case WIDX_FILE_MENU: + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) + dropdownIndex += DDIDX_ABOUT; + + switch (dropdownIndex) { + case DDIDX_LOAD_GAME: + game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + break; + case DDIDX_SAVE_GAME: + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) { + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE, s6Info->name); + } else { + tool_cancel(); + save_game(); + } + break; + case DDIDX_ABOUT: + window_about_open(); + break; + case DDIDX_OPTIONS: + window_options_open(); + break; + case DDIDX_SCREENSHOT: + RCT2_GLOBAL(RCT2_ADDRESS_SCREENSHOT_COUNTDOWN, sint8) = 10; + break; + case DDIDX_GIANT_SCREENSHOT: + screenshot_giant(); + break; + case DDIDX_QUIT_TO_MENU: + window_close_by_class(WC_MANAGE_TRACK_DESIGN); + window_close_by_class(WC_TRACK_DELETE_PROMPT); + game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); + break; + case DDIDX_EXIT_OPENRCT2: + rct2_quit(); + break; +#ifndef DISABLE_TWITCH + case DDIDX_ENABLE_TWITCH: + gTwitchEnable = !gTwitchEnable; + break; +#endif + } + break; + case WIDX_VIEW_MENU: + top_toolbar_view_menu_dropdown(dropdownIndex); + break; + case WIDX_MAP: + if (dropdownIndex == -1) + dropdownIndex = RCT2_GLOBAL(0x009DEBA2, uint16); + + switch (dropdownIndex) { + case 0: + window_map_open(); + break; + case 1: + window_viewport_open(); + break; + case 2: + window_mapgen_open(); + break; + } + break; + case WIDX_FASTFORWARD: + top_toolbar_fastforward_menu_dropdown(dropdownIndex); + break; + case WIDX_DEBUG: + top_toolbar_debug_menu_dropdown(dropdownIndex); + break; + } +} + +/** + * + * rct2: 0x0066C810 + */ +static void window_top_toolbar_invalidate() +{ + int i, x, enabledWidgets, widgetIndex, widgetWidth, firstAlignment; + rct_window *w; + rct_widget *widget; + + window_get_register(w); + colour_scheme_update(w); + + // Enable / disable buttons + window_top_toolbar_widgets[WIDX_PAUSE].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_FILE_MENU].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_ZOOM_OUT].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_ZOOM_IN].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_ROTATE].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_VIEW_MENU].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_MAP].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_LAND].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_WATER].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_SCENERY].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_PATH].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_RIDES].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_PARK].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_STAFF].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_GUESTS].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_CLEAR_SCENERY].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_FINANCES].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_RESEARCH].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_FASTFORWARD].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_CHEATS].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_DEBUG].type = gConfigGeneral.debugging_tools ? WWT_TRNBTN : WWT_EMPTY; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { + window_top_toolbar_widgets[WIDX_PAUSE].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_RIDES].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_PARK].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_STAFF].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_GUESTS].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_FINANCES].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_RESEARCH].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_CHEATS].type = WWT_EMPTY; + + if (g_editor_step != EDITOR_STEP_LANDSCAPE_EDITOR) { + window_top_toolbar_widgets[WIDX_MAP].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_LAND].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_WATER].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_SCENERY].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_PATH].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_CLEAR_SCENERY].type = WWT_EMPTY; + } + + if (g_editor_step != EDITOR_STEP_ROLLERCOASTER_DESIGNER) { + window_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_FASTFORWARD].type = WWT_EMPTY; + } + + if (g_editor_step != EDITOR_STEP_LANDSCAPE_EDITOR && g_editor_step != EDITOR_STEP_ROLLERCOASTER_DESIGNER) { + window_top_toolbar_widgets[WIDX_ZOOM_OUT].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_ZOOM_IN].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_ROTATE].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_VIEW_MENU].type = WWT_EMPTY; + } + } else { + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) || !gConfigInterface.toolbar_show_finances) + window_top_toolbar_widgets[WIDX_FINANCES].type = WWT_EMPTY; + + if (!gConfigInterface.toolbar_show_research) + window_top_toolbar_widgets[WIDX_RESEARCH].type = WWT_EMPTY; + + if (!gConfigInterface.toolbar_show_cheats) + window_top_toolbar_widgets[WIDX_CHEATS].type = WWT_EMPTY; + } + + enabledWidgets = 0; + for (i = WIDX_PAUSE; i <= WIDX_RESEARCH; i++) + if (window_top_toolbar_widgets[i].type != WWT_EMPTY) + enabledWidgets |= (1 << i); + w->enabled_widgets = enabledWidgets; + + // Align left hand side toolbar buttons + firstAlignment = 1; + x = 0; + for (int i = 0; i < countof(left_aligned_widgets_order); ++i) { + widgetIndex = left_aligned_widgets_order[i]; + widget = &window_top_toolbar_widgets[widgetIndex]; + if (widget->type == WWT_EMPTY && widgetIndex != WIDX_SEPARATOR) + continue; + + if (firstAlignment && widgetIndex == WIDX_SEPARATOR) + continue; + + widgetWidth = widget->right - widget->left; + widget->left = x; + x += widgetWidth; + widget->right = x; + x += 1; + firstAlignment = 0; + } + + // Align right hand side toolbar buttons + firstAlignment = 1; + x = max(640, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + for (int i = 0; i < countof(right_aligned_widgets_order); ++i) { + widgetIndex = right_aligned_widgets_order[i]; + widget = &window_top_toolbar_widgets[widgetIndex]; + if (widget->type == WWT_EMPTY && widgetIndex != WIDX_SEPARATOR) + continue; + + if (firstAlignment && widgetIndex == WIDX_SEPARATOR) + continue; + + widgetWidth = widget->right - widget->left; + x -= 1; + widget->right = x; + x -= widgetWidth; + widget->left = x; + firstAlignment = 0; + } + + // Footpath button pressed down + if (window_find_by_class(WC_FOOTPATH) == NULL) + w->pressed_widgets &= ~(1 << WIDX_PATH); + else + w->pressed_widgets |= (1 << WIDX_PATH); + + // Fast forward button pressed down + // if (0) + // w->pressed_widgets |= (1 << WIDX_FASTFORWARD); + // else + // w->pressed_widgets &= ~(1 << WIDX_FASTFORWARD); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint32) & 1)) + w->pressed_widgets &= ~(1 << WIDX_PAUSE); + else + w->pressed_widgets |= (1 << WIDX_PAUSE); + + // Zoomed out/in disable. Not sure where this code is in the original. + if (window_get_main()->viewport->zoom == 0){ + w->disabled_widgets |= (1 << WIDX_ZOOM_IN); + } else if (window_get_main()->viewport->zoom == 3){ + w->disabled_widgets |= (1 << WIDX_ZOOM_OUT); + } else { + w->disabled_widgets &= ~((1 << WIDX_ZOOM_IN) | (1 << WIDX_ZOOM_OUT)); + } +} + +/** + * + * rct2: 0x0066C8EC + */ +static void window_top_toolbar_paint() +{ + int x, y, imgId; + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + // Draw staff button image (setting masks to the staff colours) + if (window_top_toolbar_widgets[WIDX_STAFF].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_STAFF].left; + y = w->y + window_top_toolbar_widgets[WIDX_STAFF].top; + imgId = 5627; + if (widget_is_pressed(w, WIDX_STAFF)) + imgId++; + imgId |= (RCT2_GLOBAL(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8) << 19) | 0xA0000000 | (RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) << 24); + gfx_draw_sprite(dpi, imgId, x, y, 0); + } + + // Draw fast forward button + if (window_top_toolbar_widgets[WIDX_FASTFORWARD].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_FASTFORWARD].left + 0; + y = w->y + window_top_toolbar_widgets[WIDX_FASTFORWARD].top + 0; + if (widget_is_pressed(w, WIDX_FASTFORWARD)) + y++; + imgId = SPR_G2_FASTFORWARD; + gfx_draw_sprite(dpi, imgId, x + 6, y + 3, 0); + + + for (int i = 0; i < gGameSpeed && gGameSpeed <= 4; i++) { + gfx_draw_sprite(dpi, SPR_G2_SPEED_ARROW, x + 5 + i * 5, y + 15, 0); + } + for (int i = 0; i < 3 && i < gGameSpeed - 4 && gGameSpeed >= 5; i++) { + gfx_draw_sprite(dpi, SPR_G2_HYPER_ARROW, x + 5 + i * 6, y + 15, 0); + } + /*if (gGameSpeed >= 8) { + gfx_draw_sprite(dpi, SPR_G2_HYPER_ARROWS, x + 5, y + 15, 0); + }*/ + } + + // Draw cheats button + if (window_top_toolbar_widgets[WIDX_CHEATS].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_CHEATS].left - 1; + y = w->y + window_top_toolbar_widgets[WIDX_CHEATS].top - 1; + if (widget_is_pressed(w, WIDX_CHEATS)) + y++; + imgId = SPR_TAB_OBJECTIVE_0; + gfx_draw_sprite(dpi, imgId, x, y, 3); + } + + // Draw debug button + if (window_top_toolbar_widgets[WIDX_DEBUG].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_DEBUG].left; + y = w->y + window_top_toolbar_widgets[WIDX_DEBUG].top - 1; + if (widget_is_pressed(w, WIDX_DEBUG)) + y++; + imgId = 5201; + gfx_draw_sprite(dpi, imgId, x, y, 3); + } + + // Draw research button + if (window_top_toolbar_widgets[WIDX_RESEARCH].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_RESEARCH].left - 1; + y = w->y + window_top_toolbar_widgets[WIDX_RESEARCH].top; + if (widget_is_pressed(w, WIDX_RESEARCH)) + y++; + imgId = SPR_TAB_FINANCES_RESEARCH_0; + gfx_draw_sprite(dpi, imgId, x, y, 0); + } + + // Draw finances button + if (window_top_toolbar_widgets[WIDX_FINANCES].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_FINANCES].left + 3; + y = w->y + window_top_toolbar_widgets[WIDX_FINANCES].top + 1; + if (widget_is_pressed(w, WIDX_FINANCES)) + y++; + imgId = SPR_FINANCE; + gfx_draw_sprite(dpi, imgId, x, y, 0); + } +} + +/* rct2: 0x006E3158 */ +static void repaint_scenery_tool_down(sint16 x, sint16 y, sint16 widgetIndex){ + // ax, cx, bl + sint16 grid_x, grid_y; + int type; + // edx + rct_map_element* map_element; + uint16 flags = + VIEWPORT_INTERACTION_MASK_SCENERY & + VIEWPORT_INTERACTION_MASK_WALL & + VIEWPORT_INTERACTION_MASK_LARGE_SCENERY & + VIEWPORT_INTERACTION_MASK_BANNER; + // This is -2 as banner is 12 but flags are offset different + + // not used + rct_viewport* viewport; + get_map_coordinates_from_pos(x, y, flags, &grid_x, &grid_y, &type, &map_element, &viewport); + + switch (type){ + case VIEWPORT_INTERACTION_ITEM_SCENERY: + { + rct_scenery_entry* scenery_entry = g_smallSceneryEntries[map_element->properties.scenery.type]; + + // If can't repaint + if (!(scenery_entry->small_scenery.flags & + (SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | + SMALL_SCENERY_FLAG10))) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + game_do_command( + grid_x, + 1 | (map_element->type << 8), + grid_y, + map_element->base_height | (map_element->properties.scenery.type << 8), + GAME_COMMAND_52, + 0, + window_scenery_primary_colour | (window_scenery_secondary_colour << 8)); + break; + } + case VIEWPORT_INTERACTION_ITEM_WALL: + { + rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.type]; + + // If can't repaint + if (!(scenery_entry->wall.flags & + (WALL_SCENERY_FLAG1 | + WALL_SCENERY_FLAG2))) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + game_do_command( + grid_x, + 1 | (window_scenery_primary_colour << 8), + grid_y, + (map_element->type & MAP_ELEMENT_DIRECTION_MASK) | (map_element->base_height << 8), + GAME_COMMAND_53, + 0, + window_scenery_secondary_colour | (window_scenery_tertiary_colour << 8)); + break; + } + case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: + { + rct_scenery_entry* scenery_entry = g_largeSceneryEntries[map_element->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK]; + + // If can't repaint + if (!(scenery_entry->large_scenery.flags & + (1 << 0))) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + game_do_command( + grid_x, + 1 | ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) << 8), + grid_y, + map_element->base_height | ((map_element->properties.scenerymultiple.type >> 10) << 8), + GAME_COMMAND_54, + 0, + window_scenery_primary_colour | (window_scenery_secondary_colour << 8)); + break; + } + case VIEWPORT_INTERACTION_ITEM_BANNER: + { + rct_banner* banner = &gBanners[map_element->properties.banner.index]; + rct_scenery_entry* scenery_entry = g_bannerSceneryEntries[banner->type]; + + // If can't repaint + if (!(scenery_entry->banner.flags & + (1 << 0))) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + game_do_command( + grid_x, + 1, + grid_y, + map_element->base_height | ((map_element->properties.banner.position & 0x3) << 8), + GAME_COMMAND_55, + 0, + window_scenery_primary_colour | (window_scenery_secondary_colour << 8)); + break; + } + default: + return; + } +} + +void sub_689604(sint16 x, sint16 y, sint16* grid_x, sint16* grid_y, uint8* cl){ + int eax = x, ebx = y, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = 0; + + RCT2_CALLFUNC_X(0x00689604, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + *grid_x = eax; + *grid_y = ebx; + *cl = ecx; +} + +void sub_68964B(sint16 x, sint16 y, sint16 z, sint16* grid_x, sint16* grid_y, uint8* cl){ + int eax = x, ebx = y, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = z; + + RCT2_CALLFUNC_X(0x0068964B, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + *grid_x = eax; + *grid_y = ebx; + *cl = ecx; +} + +void sub_689692(sint16 x, sint16 y, sint16* grid_x, sint16* grid_y, uint8* cl){ + int eax = x, ebx = y, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = 0; + + RCT2_CALLFUNC_X(0x00689692, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + *grid_x = eax; + *grid_y = ebx; + *cl = ecx; +} + +void sub_6896DC(sint16 x, sint16 y, sint16 z, sint16* grid_x, sint16* grid_y, uint8* cl){ + int eax = x, ebx = y, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = z; + + RCT2_CALLFUNC_X(0x006896DC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + *grid_x = eax; + *grid_y = ebx; + *cl = ecx; +} + +void sub_6894D4(sint16 x, sint16 y, sint16 z, sint16* grid_x, sint16* grid_y){ + int eax = x, ebx = y, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = z; + + RCT2_CALLFUNC_X(0x006894D4, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + *grid_x = eax; + *grid_y = ebx; +} + +/* rct2: 0x006E1F34 + * Outputs + * eax : grid_x + * ebx : parameter_1 + * ecx : grid_y + * edx : parameter_2 + * edi : parameter_3 + */ +void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sint16* grid_y, uint32* parameter_1, uint32* parameter_2, uint32* parameter_3){ + rct_window* w = window_find_by_class(WC_SCENERY); + + if (w == NULL) + { + *grid_x = 0x8000; + return; + } + + uint8 scenery_type = selected_scenery >> 8; + // Not sure what this type is yet. + uint8 type = 0; + + if (scenery_type == 0){ + rct_scenery_entry* scenery_entry = g_smallSceneryEntries[selected_scenery]; + + if (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18){ + type = 1; + } + } + else if (scenery_type == 2 || scenery_type == 3){ + type = 1; + } + + if (type == 0){ + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) = 0; + } + else{ + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) == 0){ + // CTRL pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & (1 << 1)){ + rct_map_element* map_element; + uint16 flags = + VIEWPORT_INTERACTION_MASK_TERRAIN & + VIEWPORT_INTERACTION_MASK_RIDE & + VIEWPORT_INTERACTION_MASK_SCENERY & + VIEWPORT_INTERACTION_MASK_FOOTPATH & + VIEWPORT_INTERACTION_MASK_WALL & + VIEWPORT_INTERACTION_MASK_LARGE_SCENERY; + int interaction_type; + get_map_coordinates_from_pos(x, y, flags, NULL, NULL, &interaction_type, &map_element, NULL); + + if (interaction_type != VIEWPORT_INTERACTION_ITEM_NONE){ + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, uint16) = map_element->base_height * 8; + } + } + } + else{ + // CTRL not pressed + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & (1 << 1))){ + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) = 0; + } + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) == 0){ + // SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & (1 << 0)){ + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_X_COORDINATE, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Y_COORDINATE, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, uint16) = 0; + } + } + else{ + // SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & (1 << 0)){ + RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16) = + (RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Y_COORDINATE, sint16) - y + 4) & 0xFFF8; + + x = RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_X_COORDINATE, sint16); + y = RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Y_COORDINATE, sint16); + } + else{ + // SHIFT not pressed + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) = 0; + } + } + } + + switch (scenery_type){ + case 0: + { + // Small scenery + rct_scenery_entry* scenery = g_smallSceneryEntries[selected_scenery]; + if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ + uint8 cl = 0; + + // If CTRL not pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) == 0){ + sub_689604(x, y, grid_x, grid_y, &cl); + + if (*grid_x == (sint16)0x8000) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = 0; + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + + rct_map_element* map_element = map_get_surface_element_at(*grid_x / 32, *grid_y / 32); + + if (map_element == NULL){ + *grid_x = 0x8000; + return; + } + + sint16 z = (map_element->base_height * 8) & 0xFFF0; + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + } + else{ + sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); + + sub_68964B(x, y, z, grid_x, grid_y, &cl); + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + } + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + + if (*grid_x == (sint16)0x8000) + return; + + uint8 rotation = window_scenery_rotation; + + if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG4)){ + rotation = scenario_rand() & 0xFF; + } + + rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation &= 0x3; + + // Also places it in lower but think thats for clobering + *parameter_1 = (selected_scenery & 0xFF) << 8; + *parameter_2 = cl ^ (1 << 1) | (window_scenery_primary_colour << 8); + *parameter_3 = rotation | (window_scenery_secondary_colour << 16); + return; + } + + // If CTRL not pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) == 0){ + uint16 flags = + VIEWPORT_INTERACTION_MASK_TERRAIN & + VIEWPORT_INTERACTION_MASK_WATER; + int interaction_type = 0; + rct_map_element* map_element; + + get_map_coordinates_from_pos(x, y, flags, grid_x, grid_y, &interaction_type, &map_element, NULL); + + if (interaction_type == VIEWPORT_INTERACTION_ITEM_NONE) + { + *grid_x = 0x8000; + return; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = 0; + uint16 water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + if (water_height != 0){ + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = water_height * 16; + } + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + rct_map_element* map_element = map_get_surface_element_at(*grid_x / 32, *grid_y / 32); + + if (map_element == NULL){ + *grid_x = 0x8000; + return; + } + + sint16 z = (map_element->base_height * 8) & 0xFFF0; + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + } + else{ + sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); + sub_6894D4(x, y, z, grid_x, grid_y); + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + } + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + + if (*grid_x == (sint16)0x8000) + return; + + *grid_x &= 0xFFE0; + *grid_y &= 0xFFE0; + uint8 rotation = window_scenery_rotation; + + if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG4)){ + rotation = scenario_rand() & 0xFF; + } + + rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation &= 0x3; + + // Also places it in lower but think thats for clobering + *parameter_1 = (selected_scenery & 0xFF) << 8; + *parameter_2 = 0 | (window_scenery_primary_colour << 8); + *parameter_3 = rotation | (window_scenery_secondary_colour << 16); + break; + } + case 1: + { + // Path bits + + uint16 flags = + VIEWPORT_INTERACTION_MASK_FOOTPATH & + VIEWPORT_INTERACTION_MASK_FOOTPATH_ITEM; + int interaction_type = 0; + rct_map_element* map_element; + + get_map_coordinates_from_pos(x, y, flags, grid_x, grid_y, &interaction_type, &map_element, NULL); + + if (interaction_type == VIEWPORT_INTERACTION_ITEM_NONE) + { + *grid_x = 0x8000; + return; + } + + *parameter_1 = 0 | ((map_element->properties.path.type & 0x7) << 8); + *parameter_2 = map_element->base_height | ((map_element->properties.path.type >> 4) << 8); + if (map_element->type & 1){ + *parameter_2 |= 0x8000; + } + *parameter_3 = (selected_scenery & 0xFF) + 1; + break; + } + case 2: + { + // Walls + uint8 cl; + // If CTRL not pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) == 0){ + sub_689692(x, y, grid_x, grid_y, &cl); + + if (*grid_x == (sint16)0x8000) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = 0; + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + rct_map_element* map_element = map_get_surface_element_at(*grid_x / 32, *grid_y / 32); + + if (map_element == NULL){ + *grid_x = 0x8000; + return; + } + + sint16 z = (map_element->base_height * 8) & 0xFFF0; + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + } + else{ + sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); + sub_6896DC(x, y, z, grid_x, grid_y, &cl); + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + } + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + + if (*grid_x == (sint16)0x8000) + return; + + RCT2_GLOBAL(0x00F64F15, uint8) = window_scenery_secondary_colour; + RCT2_GLOBAL(0x00F64F16, uint8) = window_scenery_tertiary_colour; + // Also places it in lower but think thats for clobering + *parameter_1 = (selected_scenery & 0xFF) << 8; + *parameter_2 = cl | (window_scenery_primary_colour << 8); + *parameter_3 = 0; + break; + } + case 3: + { + // Large scenery + + // If CTRL not pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) == 0){ + sub_68A15E(x, y, grid_x, grid_y, NULL, NULL); + + if (*grid_x == (sint16)0x8000) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = 0; + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + rct_map_element* map_element = map_get_surface_element_at(*grid_x / 32, *grid_y / 32); + + if (map_element == NULL){ + *grid_x = 0x8000; + return; + } + + sint16 z = (map_element->base_height * 8) & 0xFFF0; + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + } + else{ + sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); + sub_6894D4(x, y, z, grid_x, grid_y); + + // If SHIFT pressed + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + z += RCT2_GLOBAL(RCT2_ADDRESS_SHIFT_PRESS_Z_VECTOR, sint16); + } + + if (z < 16){ + z = 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = z; + } + + if (*grid_x == (sint16)0x8000) + return; + + *grid_x &= 0xFFE0; + *grid_y &= 0xFFE0; + + uint8 rotation = window_scenery_rotation; + rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation &= 0x3; + + *parameter_1 = (rotation << 8); + *parameter_2 = window_scenery_primary_colour | (window_scenery_secondary_colour << 8); + *parameter_3 = selected_scenery & 0xFF; + break; + } + case 4: + { + // Banner + + uint16 flags = + VIEWPORT_INTERACTION_MASK_FOOTPATH & + VIEWPORT_INTERACTION_MASK_FOOTPATH_ITEM; + int interaction_type = 0; + rct_map_element* map_element; + + get_map_coordinates_from_pos(x, y, flags, grid_x, grid_y, &interaction_type, &map_element, NULL); + + if (interaction_type == VIEWPORT_INTERACTION_ITEM_NONE) + { + *grid_x = 0x8000; + return; + } + + uint8 rotation = window_scenery_rotation; + rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation &= 0x3; + + sint16 z = map_element->base_height; + + if (map_element->properties.path.type & (1 << 2)){ + if (rotation != ((map_element->properties.path.type & 3) ^ 2)){ + z += 2; + } + } + + z /= 2; + + // Also places it in lower but think thats for clobering + *parameter_1 = (selected_scenery & 0xFF) << 8; + *parameter_2 = z | (rotation << 8); + *parameter_3 = window_scenery_primary_colour; + break; + } + } +} + +/** + * rct2: 0x6e2cc6 + */ +static void window_top_toolbar_scenery_tool_down(short x, short y, rct_window* w, short widgetIndex){ + scenery_remove_ghost_tool_placement(); + if (window_scenery_is_repaint_scenery_tool_on & 1){ + repaint_scenery_tool_down(x, y, widgetIndex); + return; + } + + int selected_tab = window_scenery_selected_scenery_by_tab[window_scenery_active_tab_index]; + uint8 scenery_type = (selected_tab & 0xFF00) >> 8; + uint8 selected_scenery = selected_tab & 0xFF; + + if (selected_tab == -1) return; + + sint16 grid_x, grid_y; + int ebp = selected_tab; + uint32 parameter_1, parameter_2, parameter_3; + + sub_6E1F34(x, y, selected_tab, &grid_x, &grid_y, ¶meter_1, ¶meter_2, ¶meter_3); + + if (grid_x == (sint16)0x8000)return; + + switch (scenery_type){ + case 0: + { + int cluster_size = 1; + if (window_scenery_is_build_cluster_tool_on){ + cluster_size = 35; + } + + for (; cluster_size > 0; cluster_size--){ + + int cluster_z_coordinate = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16); + rct_scenery_entry* scenery = g_smallSceneryEntries[(parameter_1 >> 8) & 0xFF]; + + sint16 cur_grid_x = grid_x; + sint16 cur_grid_y = grid_y; + + if (window_scenery_is_build_cluster_tool_on){ + if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ + parameter_2 &= 0xFF00; + parameter_2 |= scenario_rand() & 3; + } + + cur_grid_x += ((scenario_rand() % 16) - 8) * 32; + cur_grid_y += ((scenario_rand() % 16) - 8) * 32; + + if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG4)){ + RCT2_GLOBAL(0x00F64EC0, uint16)++; + RCT2_GLOBAL(0x00F64EC0, uint16) &= 3; + } + } + + uint8 bl = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + bl = 20; + } + uint8 success = 0; + + for (; bl != 0; bl--){ + RCT2_GLOBAL(0x009A8C29, uint8) |= 1; + + int ebx = parameter_1; + ebx &= 0xFF00; + if (window_scenery_is_build_cluster_tool_on){ + ebx |= 0x9; + } + else{ + ebx |= GAME_COMMAND_FLAG_APPLY; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1161; + + int cost = game_do_command(cur_grid_x, ebx, cur_grid_y, parameter_2, GAME_COMMAND_PLACE_SCENERY, RCT2_GLOBAL(0x00F64EC0, uint8) | (parameter_3 & 0xFFFF0000), RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16)); + + + RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; + + if (cost != MONEY32_UNDEFINED){ + window_close_by_class(WC_ERROR); + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + success = 1; + break; + } + + if (RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 827 || + RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 1032){ + break; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; + } + + if (!success && !window_scenery_is_build_cluster_tool_on){ + sound_play_panned(SOUND_ERROR, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + return; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = cluster_z_coordinate; + } + break; + } + case 1: + { + // Path Bits + int ebx = parameter_1; + ebx &= 0xFF00; + ebx |= 0x81; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1161; + + int cost = game_do_command(grid_x, ebx, grid_y, parameter_2, GAME_COMMAND_PLACE_PATH, parameter_3, 0); + + if (cost == MONEY32_UNDEFINED){ + return; + } + + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + break; + } + case 2: + { + // Walls + uint8 bl = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + bl = 20; + } + + for (; bl != 0; bl--){ + RCT2_GLOBAL(0x009A8C29, uint8) |= 1; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1811; + + int ebx = (parameter_1 & 0xFF00) | 1; + + int cost = game_do_command(grid_x, ebx, grid_y, parameter_2, GAME_COMMAND_41, RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16), RCT2_GLOBAL(0x00F64F15, uint16)); + + RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; + + if (cost != MONEY32_UNDEFINED){ + window_close_by_class(WC_ERROR); + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + return; + } + + if (RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 827 || + RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 1032){ + break; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; + } + + sound_play_panned(SOUND_ERROR, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + break; + } + case 3: + { + // Large Scenery + uint8 bl = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + bl = 20; + } + + for (; bl != 0; bl--){ + RCT2_GLOBAL(0x009A8C29, uint8) |= 1; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1161; + + int ebx = (parameter_1 & 0xFF00) | 1; + + int cost = game_do_command(grid_x, ebx, grid_y, parameter_2, GAME_COMMAND_PLACE_LARGE_SCENERY, parameter_3, RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16)); + + + RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; + + if (cost != MONEY32_UNDEFINED){ + window_close_by_class(WC_ERROR); + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + return; + } + + if (RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 827 || + RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 1032){ + break; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; + } + + sound_play_panned(SOUND_ERROR, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + } + break; + case 4: + { + // Banners + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1161; + + // The return value will be banner id but the input is colour (param 3) + int banner_id = parameter_3; + + int cost; + { + int esi = 0, eax = grid_x, ecx = grid_y, edx = parameter_2, ebx = (parameter_1 & 0xFF00) | 1; + cost = game_do_command_p(GAME_COMMAND_PLACE_BANNER, &eax, &ebx, &ecx, &edx, &esi, &banner_id, &ebp); + } + + if (cost == MONEY32_UNDEFINED)return; + + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + + window_banner_open(banner_id); + break; + } + } +} + +/** +* +* rct2: 0x0068E213 +*/ +void top_toolbar_tool_update_scenery_clear(sint16 x, sint16 y){ + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + + rct_xy16 mapTile = { 0 }; + sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + + if (mapTile.x == (sint16)0x8000){ + if (RCT2_GLOBAL(0x00F1AD62, money32) != MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F1AD62, money32) = MONEY32_UNDEFINED; + window_invalidate_by_class(WC_CLEAR_SCENERY); + } + return; + } + + uint8 state_changed = 0; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != 4){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + state_changed++; + } + + sint16 tool_size = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + if (tool_size == 0) + tool_size = 1; + + sint16 tool_length = (tool_size - 1) * 32; + + // Move to tool bottom left + mapTile.x -= (tool_size - 1) * 16; + mapTile.y -= (tool_size - 1) * 16; + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + state_changed++; + } + + mapTile.x += tool_length; + mapTile.y += tool_length; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + state_changed++; + } + + map_invalidate_selection_rect(); + if (!state_changed) + return; + + money32 cost = map_clear_scenery( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16), + 0 + ); + + if (RCT2_GLOBAL(0x00F1AD62, money32) != cost){ + RCT2_GLOBAL(0x00F1AD62, money32) = cost; + window_invalidate_by_class(WC_CLEAR_SCENERY); + return; + } +} + +void top_toolbar_tool_update_land_paint(sint16 x, sint16 y){ + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + + rct_xy16 mapTile = { 0 }; + sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + + if (mapTile.x == (sint16)0x8000){ + if (RCT2_GLOBAL(0x00F1AD62, money32) != MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F1AD62, money32) = MONEY32_UNDEFINED; + window_invalidate_by_class(WC_CLEAR_SCENERY); + } + return; + } + + uint8 state_changed = 0; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != 4){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + state_changed++; + } + + sint16 tool_size = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + if (tool_size == 0) + tool_size = 1; + + sint16 tool_length = (tool_size - 1) * 32; + + // Move to tool bottom left + mapTile.x -= (tool_size - 1) * 16; + mapTile.y -= (tool_size - 1) * 16; + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + state_changed++; + } + + mapTile.x += tool_length; + mapTile.y += tool_length; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + state_changed++; + } + + map_invalidate_selection_rect(); + if (!state_changed) + return; +} + +/** +* +* rct2: 0x00664280 +*/ +void top_toolbar_tool_update_land(sint16 x, sint16 y){ + map_invalidate_selection_rect(); + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) == 3){ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))) + return; + + money32 lower_cost = selection_lower_land(0); + money32 raise_cost = selection_raise_land(0); + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) != raise_cost || + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) != lower_cost){ + RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) = raise_cost; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) = lower_cost; + window_invalidate_by_class(WC_LAND); + } + return; + } + + sint16 tool_size = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + rct_xy16 mapTile = { .x = x, .y = y }; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + if (tool_size == 1){ + int direction; + screen_pos_to_map_pos(&mapTile.x, &mapTile.y, &direction); + + if (mapTile.x == (sint16)0x8000){ + money32 lower_cost = MONEY32_UNDEFINED; + money32 raise_cost = MONEY32_UNDEFINED; + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) != raise_cost || + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) != lower_cost){ + RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) = raise_cost; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) = lower_cost; + window_invalidate_by_class(WC_LAND); + } + return; + } + + uint8 state_changed = 0; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != direction){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = direction; + state_changed++; + } + + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + state_changed++; + } + + map_invalidate_selection_rect(); + if (!state_changed) + return; + + money32 lower_cost = selection_lower_land(0); + money32 raise_cost = selection_raise_land(0); + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) != raise_cost || + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) != lower_cost){ + RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) = raise_cost; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) = lower_cost; + window_invalidate_by_class(WC_LAND); + } + return; + } + + sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + + if (mapTile.x == (sint16)0x8000){ + money32 lower_cost = MONEY32_UNDEFINED; + money32 raise_cost = MONEY32_UNDEFINED; + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) != raise_cost || + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) != lower_cost){ + RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) = raise_cost; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) = lower_cost; + window_invalidate_by_class(WC_LAND); + } + return; + } + + uint8 state_changed = 0; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != 4){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + state_changed++; + } + + + if (tool_size == 0) + tool_size = 1; + + sint16 tool_length = (tool_size - 1) * 32; + + // Move to tool bottom left + mapTile.x -= (tool_size - 1) * 16; + mapTile.y -= (tool_size - 1) * 16; + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + state_changed++; + } + + mapTile.x += tool_length; + mapTile.y += tool_length; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + state_changed++; + } + + map_invalidate_selection_rect(); + if (!state_changed) + return; + + money32 lower_cost = selection_lower_land(0); + money32 raise_cost = selection_raise_land(0); + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) != raise_cost || + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) != lower_cost){ + RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) = raise_cost; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, money32) = lower_cost; + window_invalidate_by_class(WC_LAND); + } +} + +/** +* +* rct2: 0x006E6BDC +*/ +void top_toolbar_tool_update_water(sint16 x, sint16 y){ + map_invalidate_selection_rect(); + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) == 3){ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))) + return; + + money32 lower_cost = lower_water( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16), + 0); + + money32 raise_cost = raise_water( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16), + 0); + + if (RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, money32) != raise_cost || + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, money32) != lower_cost){ + RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, money32) = raise_cost; + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, money32) = lower_cost; + window_invalidate_by_class(WC_WATER); + } + return; + } + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + + rct_xy16 mapTile = { 0 }; + int interaction_type = 0; + get_map_coordinates_from_pos( + x, + y, + VIEWPORT_INTERACTION_MASK_TERRAIN & VIEWPORT_INTERACTION_MASK_WATER, + &mapTile.x, + &mapTile.y, + &interaction_type, + NULL, + NULL); + + if (interaction_type == VIEWPORT_INTERACTION_ITEM_NONE){ + if (RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, money32) != MONEY32_UNDEFINED || + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, money32) != MONEY32_UNDEFINED){ + RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, money32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, money32) = MONEY32_UNDEFINED; + window_invalidate_by_class(WC_WATER); + } + return; + } + + mapTile.x += 16; + mapTile.y += 16; + + uint8 state_changed = 0; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != 4){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + state_changed++; + } + + sint16 tool_size = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + if (tool_size == 0) + tool_size = 1; + + sint16 tool_length = (tool_size - 1) * 32; + + // Move to tool bottom left + mapTile.x -= (tool_size - 1) * 16; + mapTile.y -= (tool_size - 1) * 16; + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + state_changed++; + } + + mapTile.x += tool_length; + mapTile.y += tool_length; + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) != mapTile.x){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + state_changed++; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) != mapTile.y){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + state_changed++; + } + + map_invalidate_selection_rect(); + if (!state_changed) + return; + + money32 lower_cost = lower_water( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16), + 0); + + money32 raise_cost = raise_water( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16), + 0); + + if (RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, money32) != raise_cost || + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, money32) != lower_cost){ + RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, money32) = raise_cost; + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, money32) = lower_cost; + window_invalidate_by_class(WC_WATER); + } +} + +/* rct2: 0x006E24F6 + * On failure returns MONEY32_UNDEFINED + * On success places ghost scenery and returns cost to place proper + */ +money32 try_place_ghost_scenery(rct_xy16 map_tile, uint32 parameter_1, uint32 parameter_2, uint32 parameter_3, uint16 selected_tab){ + scenery_remove_ghost_tool_placement(); + + uint8 scenery_type = (selected_tab & 0xFF00) >> 8; + uint8 selected_scenery = selected_tab & 0xFF; + money32 cost = 0; + rct_map_element* mapElement; + + switch (scenery_type){ + case 0: + // Small Scenery + //6e252b + cost = game_do_command( + map_tile.x, + parameter_1 | 0x69, + map_tile.y, + parameter_2, + GAME_COMMAND_PLACE_SCENERY, + parameter_3, + RCT2_GLOBAL(0x00F64ED4, sint16)); + + if (cost == MONEY32_UNDEFINED) + return cost; + + RCT2_GLOBAL(0x00F64EC4, sint16) = map_tile.x; + RCT2_GLOBAL(0x00F64EC6, sint16) = map_tile.y; + RCT2_GLOBAL(0x00F64EC0, uint16) = (uint16)(parameter_3 & 0xFFFF); + RCT2_GLOBAL(0x00F64EDA, sint16) = selected_tab; + + mapElement = RCT2_GLOBAL(0x00F64EBC, rct_map_element*); + RCT2_GLOBAL(0x00F64F09, uint8) = mapElement->base_height; + RCT2_GLOBAL(0x00F64F0C, uint8) = mapElement->type; + if (RCT2_GLOBAL(0x00F64F14, uint8) & (1 << 1)){ + viewport_set_visibility(4); + } + else{ + viewport_set_visibility(5); + } + + RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 0); + break; + case 1: + // Path Bits + //6e265b + cost = game_do_command( + map_tile.x, + parameter_1 | 0xE9, + map_tile.y, + parameter_2, + GAME_COMMAND_PLACE_PATH, + parameter_3, + 0); + + if (cost == MONEY32_UNDEFINED) + return cost; + + RCT2_GLOBAL(0x00F64EC4, sint16) = map_tile.x; + RCT2_GLOBAL(0x00F64EC6, sint16) = map_tile.y; + RCT2_GLOBAL(0x00F64F09, uint8) = (parameter_2 & 0xFF); + RCT2_GLOBAL(0x00F64F0F, uint8) = ((parameter_1 >> 8) & 0xFF); + RCT2_GLOBAL(0x00F64F10, uint8) = ((parameter_2 >> 8) & 0xFF); + RCT2_GLOBAL(0x00F64EAC, uint32) = parameter_3; + + RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 1); + break; + case 2: + // Walls + //6e26b0 + cost = game_do_command( + map_tile.x, + parameter_1 | 0x69, + map_tile.y, + parameter_2, + GAME_COMMAND_41, + RCT2_GLOBAL(0x00F64ED4, uint16), + RCT2_GLOBAL(0x00F64F15, uint16)); + + if (cost == MONEY32_UNDEFINED) + return cost; + + RCT2_GLOBAL(0x00F64EC4, sint16) = map_tile.x; + RCT2_GLOBAL(0x00F64EC6, sint16) = map_tile.y; + RCT2_GLOBAL(0x00F64F11, uint8) = (parameter_2 & 0xFF); + + mapElement = RCT2_GLOBAL(0x00F64EBC, rct_map_element*); + RCT2_GLOBAL(0x00F64F09, uint8) = mapElement->base_height; + + RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 2); + break; + case 3: + // Large Scenery + //6e25a7 + cost = game_do_command( + map_tile.x, + parameter_1 | 0x69, + map_tile.y, + parameter_2, + GAME_COMMAND_PLACE_LARGE_SCENERY, + parameter_3, + RCT2_GLOBAL(0x00F64ED4, uint16)); + + if (cost == MONEY32_UNDEFINED) + return cost; + + RCT2_GLOBAL(0x00F64EC4, sint16) = map_tile.x; + RCT2_GLOBAL(0x00F64EC6, sint16) = map_tile.y; + RCT2_GLOBAL(0x00F64EC0, uint8) = ((parameter_1 >> 8) & 0xFF); + + mapElement = RCT2_GLOBAL(0x00F64EBC, rct_map_element*); + RCT2_GLOBAL(0x00F64F09, uint8) = mapElement->base_height; + + if (RCT2_GLOBAL(0x00F64F14, uint8) & (1 << 1)){ + viewport_set_visibility(4); + } + else{ + viewport_set_visibility(5); + } + + RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 3); + break; + case 4: + // Banners + //6e2612 + cost = game_do_command( + map_tile.x, + parameter_1 | 0x69, + map_tile.y, + parameter_2, + GAME_COMMAND_PLACE_BANNER, + parameter_3, + 0); + + if (cost == MONEY32_UNDEFINED) + return cost; + + RCT2_GLOBAL(0x00F64EC4, sint16) = map_tile.x; + RCT2_GLOBAL(0x00F64EC6, sint16) = map_tile.y; + RCT2_GLOBAL(0x00F64F09, uint8) = (parameter_2 & 0xFF); + RCT2_GLOBAL(0x00F64EC0, uint8) = ((parameter_2 >> 8) & 0xFF); + RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 4); + break; + } + + return cost; +} + +/** +* +* rct2: 0x006E287B +*/ +void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ + map_invalidate_selection_rect(); + map_invalidate_map_selection_tiles(); + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~((1 << 0) | (1 << 1)); + + if (window_scenery_is_repaint_scenery_tool_on) + return; + + sint16 selected_tab = window_scenery_selected_scenery_by_tab[window_scenery_active_tab_index]; + + if (selected_tab == -1){ + scenery_remove_ghost_tool_placement(); + return; + } + + uint8 scenery_type = (selected_tab & 0xFF00) >> 8; + uint8 selected_scenery = selected_tab & 0xFF; + rct_xy16 mapTile = { 0 }; + uint32 parameter1, parameter2, parameter3; + + sub_6E1F34(x, y, selected_tab, &mapTile.x, &mapTile.y, ¶meter1, ¶meter2, ¶meter3); + + if (mapTile.x == (sint16)0x8000){ + scenery_remove_ghost_tool_placement(); + return; + } + + rct_scenery_entry* scenery; + uint8 bl; + money32 cost; + + switch (scenery_type){ + case 0: + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + + scenery = g_smallSceneryEntries[selected_scenery]; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = ((parameter2 & 0xFF) ^ 2) + 6; + } + + map_invalidate_selection_rect(); + + // If no change in ghost placement + if ((RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 0)) && + mapTile.x == RCT2_GLOBAL(0x00F64EC4, sint16) && + mapTile.y == RCT2_GLOBAL(0x00F64EC6, sint16) && + (parameter2 & 0xFF) == RCT2_GLOBAL(0x00F64F0E, uint8)&& + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) == RCT2_GLOBAL(0x00F64F0A, sint16) && + RCT2_GLOBAL(0x00F64EDA, uint16) == selected_tab){ + return; + } + + scenery_remove_ghost_tool_placement(); + + RCT2_GLOBAL(0x00F64F0E, uint8) = (parameter2 & 0xFF); + RCT2_GLOBAL(0x00F64F0A, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16); + + bl = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + bl = 20; + } + + for (; bl != 0; bl--){ + cost = try_place_ghost_scenery( + mapTile, + parameter1, + parameter2, + parameter3, + selected_tab); + + if (cost != MONEY32_UNDEFINED) + break; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; + } + + RCT2_GLOBAL(0x00F64EB4, money32) = cost; + break; + case 1: + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + + map_invalidate_selection_rect(); + + // If no change in ghost placement + if ((RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 1)) && + mapTile.x == RCT2_GLOBAL(0x00F64EC4, sint16) && + mapTile.y == RCT2_GLOBAL(0x00F64EC6, sint16) && + (parameter2 & 0xFF) == RCT2_GLOBAL(0x00F64F09, uint8)){ + return; + } + + scenery_remove_ghost_tool_placement(); + + cost = try_place_ghost_scenery( + mapTile, + parameter1, + parameter2, + parameter3, + selected_tab); + + RCT2_GLOBAL(0x00F64EB4, money32) = cost; + break; + case 2: + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 10 + parameter2 & 0xFF; + + map_invalidate_selection_rect(); + + // If no change in ghost placement + if ((RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 2)) && + mapTile.x == RCT2_GLOBAL(0x00F64EC4, sint16) && + mapTile.y == RCT2_GLOBAL(0x00F64EC6, sint16) && + (parameter2 & 0xFF) == RCT2_GLOBAL(0x00F64F11, uint8) && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) == RCT2_GLOBAL(0x00F64F0A, sint16) + ){ + return; + } + + scenery_remove_ghost_tool_placement(); + + RCT2_GLOBAL(0x00F64F11, uint8) = (parameter2 & 0xFF); + RCT2_GLOBAL(0x00F64F0A, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16); + + bl = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + bl = 20; + } + + cost = 0; + for (; bl != 0; bl--){ + cost = try_place_ghost_scenery( + mapTile, + parameter1, + parameter2, + parameter3, + selected_tab); + + if (cost != MONEY32_UNDEFINED) + break; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; + } + + RCT2_GLOBAL(0x00F64EB4, money32) = cost; + break; + case 3: + scenery = g_largeSceneryEntries[selected_scenery]; + rct_xy16* selectedTile = gMapSelectionTiles; + + for (rct_large_scenery_tile* tile = scenery->large_scenery.tiles; tile->x_offset != (sint16)0xFFFF; tile++){ + rct_xy16 tileLocation = { + .x = tile->x_offset, + .y = tile->y_offset + }; + + rotate_map_coordinates(&tileLocation.x, &tileLocation.y, (parameter1 >> 8) & 0xFF); + + tileLocation.x += mapTile.x; + tileLocation.y += mapTile.y; + + selectedTile->x = tileLocation.x; + selectedTile->y = tileLocation.y; + selectedTile++; + } + selectedTile->x = 0xFFFF; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 1); + map_invalidate_map_selection_tiles(); + + // If no change in ghost placement + if ((RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 3)) && + mapTile.x == RCT2_GLOBAL(0x00F64EC4, sint16) && + mapTile.y == RCT2_GLOBAL(0x00F64EC6, sint16) && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) == RCT2_GLOBAL(0x00F64F0A, sint16) && + (parameter3 & 0xFFFF) == RCT2_GLOBAL(0x00F64EDA, uint16)){ + return; + } + + scenery_remove_ghost_tool_placement(); + + RCT2_GLOBAL(0x00F64EDA, uint16) = (parameter3 & 0xFFFF); + RCT2_GLOBAL(0x00F64F0A, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16); + + bl = 1; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ + bl = 20; + } + + cost = 0; + for (; bl != 0; bl--){ + cost = try_place_ghost_scenery( + mapTile, + parameter1, + parameter2, + parameter3, + selected_tab); + + if (cost != MONEY32_UNDEFINED) + break; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; + } + + RCT2_GLOBAL(0x00F64EB4, money32) = cost; + break; + case 4: + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapTile.y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapTile.x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapTile.y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + + map_invalidate_selection_rect(); + + // If no change in ghost placement + if ((RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 4)) && + mapTile.x == RCT2_GLOBAL(0x00F64EC4, sint16) && + mapTile.y == RCT2_GLOBAL(0x00F64EC6, sint16) && + (parameter2 & 0xFF) == RCT2_GLOBAL(0x00F64F09, uint8) && + ((parameter2 >> 8) & 0xFF) == RCT2_GLOBAL(0x00F64EC0, uint8)){ + return; + } + + scenery_remove_ghost_tool_placement(); + + cost = try_place_ghost_scenery( + mapTile, + parameter1, + parameter2, + parameter3, + selected_tab); + + RCT2_GLOBAL(0x00F64EB4, money32) = cost; + break; + } +} + +/** + * + * rct2: 0x0066CB25 + */ +static void window_top_toolbar_tool_update() +{ + short widgetIndex; + rct_window *w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + switch (widgetIndex){ + case WIDX_CLEAR_SCENERY: + top_toolbar_tool_update_scenery_clear(x, y); + break; + case WIDX_LAND: + if (LandPaintMode) + top_toolbar_tool_update_land_paint(x, y); + else + top_toolbar_tool_update_land(x, y); + break; + case WIDX_WATER: + top_toolbar_tool_update_water(x, y); + break; + case WIDX_SCENERY: + top_toolbar_tool_update_scenery(x, y); + break; + } +} + +/** + * rct2: 0x0066CB73 + */ +static void window_top_toolbar_tool_down(){ + short widgetIndex; + rct_window* w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + switch (widgetIndex){ + case WIDX_CLEAR_SCENERY: + if (!RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0)) + break; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3438; + + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + 0, + GAME_COMMAND_CLEAR_SCENERY, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 12; + break; + case WIDX_LAND: + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16)&(1 << 0)){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1387; + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) | (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) << 8), + GAME_COMMAND_CHANGE_SURFACE_STYLE, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 3; + } + break; + case WIDX_WATER: + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16)&(1 << 0)){ + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 3; + } + break; + case WIDX_SCENERY: + window_top_toolbar_scenery_tool_down(x, y, w, widgetIndex); + break; + } +} + +/** +* +* rct2: 0x006644DD +*/ +money32 selection_raise_land(uint8 flags) +{ + int centreX = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16)) / 2; + int centreY = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16)) / 2; + centreX += 16; + centreY += 16; + + uint32 xBounds = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) & 0xFFFF) | (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) << 16); + uint32 yBounds = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) & 0xFFFF) | (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) << 16); + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = STR_CANT_RAISE_LAND_HERE; + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) == 0) { + return game_do_command(centreX, flags, centreY, xBounds, GAME_COMMAND_EDIT_LAND_SMOOTH, 1, yBounds); + } else { + return game_do_command(centreX, flags, centreY, xBounds, GAME_COMMAND_RAISE_LAND, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16), yBounds); + } +} + +/** +* +* rct2: 0x006645B3 +*/ +money32 selection_lower_land(uint8 flags) +{ + int centreX = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16)) / 2; + int centreY = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16)) / 2; + centreX += 16; + centreY += 16; + + uint32 xBounds = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) & 0xFFFF) | (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) << 16); + uint32 yBounds = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) & 0xFFFF) | (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) << 16); + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = STR_CANT_LOWER_LAND_HERE; + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) == 0) { + return game_do_command(centreX, flags, centreY, xBounds, GAME_COMMAND_EDIT_LAND_SMOOTH, 0xFFFF, yBounds); + } else { + return game_do_command(centreX, flags, centreY, xBounds, GAME_COMMAND_LOWER_LAND, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16), yBounds); + } +} + +/** +* part of window_top_toolbar_tool_drag(0x0066CB4E) +* rct2: 0x00664454 +*/ +void window_top_toolbar_land_tool_drag(short x, short y) +{ + rct_window *window = window_find_from_point(x, y); + if (!window) + return; + int widget_index = window_find_widget_from_point(window, x, y); + if (widget_index == 0xFFFF) + return; + rct_widget *widget = &window->widgets[widget_index]; + if (widget->type != WWT_VIEWPORT) + return; + rct_viewport *viewport = window->viewport; + if (!viewport) + return; + + sint16 tile_height = -16 / (1 << viewport->zoom); + + int y_diff = y - RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16); + + if (y_diff <= tile_height) { + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) += tile_height; + + selection_raise_land(GAME_COMMAND_FLAG_APPLY); + + RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, uint32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, uint32) = MONEY32_UNDEFINED; + return; + } + + if (y_diff >= -tile_height) { + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) -= tile_height; + + selection_lower_land(GAME_COMMAND_FLAG_APPLY); + + RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, uint32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_LOWER_COST, uint32) = MONEY32_UNDEFINED; + + return; + } +} + +/** +* part of window_top_toolbar_tool_drag(0x0066CB4E) +* rct2: 0x006E6D4B +*/ +void window_top_toolbar_water_tool_drag(short x, short y) +{ + rct_window *window = window_find_from_point(x, y); + if (!window) + return; + int widget_index = window_find_widget_from_point(window, x, y); + if (widget_index == 0xFFFF) + return; + rct_widget *widget = &window->widgets[widget_index]; + if (widget->type != WWT_VIEWPORT) + return; + rct_viewport *viewport = window->viewport; + if (!viewport) + return; + + sint16 dx = 0xFFF0; + dx >>= viewport->zoom; + + y -= RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16); + + if (y <= dx) { + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) += dx; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = STR_CANT_RAISE_WATER_LEVEL_HERE; + + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + dx, + GAME_COMMAND_RAISE_WATER, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, uint32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, uint32) = MONEY32_UNDEFINED; + + return; + } + + dx = -dx; + + if (y >= dx) { + RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) += dx; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = STR_CANT_LOWER_WATER_LEVEL_HERE; + + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + dx, + GAME_COMMAND_LOWER_WATER, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, uint32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, uint32) = MONEY32_UNDEFINED; + + return; + } +} + +/** + * + * rct2: 0x0066CB4E + */ +static void window_top_toolbar_tool_drag() +{ + short widgetIndex; + rct_window *w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + switch (widgetIndex){ + case WIDX_CLEAR_SCENERY: + if (window_find_by_class(WC_ERROR) != NULL) + break; + + if (!RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0)) + break; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3438; + + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + 0, + GAME_COMMAND_CLEAR_SCENERY, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 12; + break; + case WIDX_LAND: + // Custom setting to only change land style instead of raising or lowering land + if (LandPaintMode) { + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16)&(1 << 0)){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1387; + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + 1, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) | (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) << 8), + GAME_COMMAND_CHANGE_SURFACE_STYLE, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + ); + // The tool is set to 12 here instead of 3 so that the dragging cursor is not the elevation change cursor + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 12; + } + } else { + window_top_toolbar_land_tool_drag(x, y); + } + break; + case WIDX_WATER: + window_top_toolbar_water_tool_drag(x, y); + break; + case WIDX_SCENERY: + if (window_scenery_is_repaint_scenery_tool_on & 1) + window_top_toolbar_scenery_tool_down(x, y, w, widgetIndex); + break; + } +} + + +void top_toolbar_init_fastforward_menu(rct_window* w, rct_widget* widget) { + int num_items = 4; + gDropdownItemsFormat[0] = 1156; + gDropdownItemsFormat[1] = 1156; + gDropdownItemsFormat[2] = 1156; + gDropdownItemsFormat[3] = 1156; + if (gConfigGeneral.debugging_tools) { + gDropdownItemsFormat[4] = 0; + gDropdownItemsFormat[5] = 1156; + gDropdownItemsArgs[5] = 5146; + num_items = 6; + } + + gDropdownItemsArgs[0] = 5142; + gDropdownItemsArgs[1] = 5143; + gDropdownItemsArgs[2] = 5144; + gDropdownItemsArgs[3] = 5145; + + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[0] | 0x80, + 0, + num_items + ); + + // Set checkmarks + if (gGameSpeed <= 4) + gDropdownItemsChecked |= (1 << (gGameSpeed - 1)); + if (gGameSpeed == 8) + gDropdownItemsChecked |= (1 << 5); + + if (gConfigGeneral.debugging_tools) + RCT2_GLOBAL(0x9DEBA2, uint16) = (gGameSpeed == 8 ? 0 : gGameSpeed); + else + RCT2_GLOBAL(0x9DEBA2, uint16) = (gGameSpeed >= 4 ? 0 : gGameSpeed); +} + +void top_toolbar_fastforward_menu_dropdown(short dropdownIndex) { + if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x9DEBA2, uint16); + rct_window* w = window_get_main(); + if (w) { + if (dropdownIndex >= 0 && dropdownIndex <= 5) { + gGameSpeed = dropdownIndex + 1; + if (gGameSpeed >= 5) + gGameSpeed = 8; + window_invalidate(w); + } + } +} + +void top_toolbar_init_debug_menu(rct_window* w, rct_widget* widget) { + gDropdownItemsFormat[0] = STR_DEBUG_DROPDOWN_CONSOLE; + gDropdownItemsFormat[1] = STR_DEBUG_DROPDOWN_TILE_INSPECTOR; + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1] | 0x80, + 0, + 2 + ); + + RCT2_GLOBAL(0x9DEBA2, uint16) = 0; +} + +void top_toolbar_debug_menu_dropdown(short dropdownIndex) { + if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x9DEBA2, uint16); + rct_window* w = window_get_main(); + if (w) { + switch (dropdownIndex) { + case DDIDX_CONSOLE: + console_open(); + break; + case DDIDX_TILE_INSPECTOR: + window_tile_inspector_open(); + break; + } + } +} + +/** + * + * rct2: 0x0066CDE4 + */ +void top_toolbar_init_view_menu(rct_window* w, rct_widget* widget) { + gDropdownItemsFormat[0] = 1156; + gDropdownItemsFormat[1] = 1156; + gDropdownItemsFormat[2] = 1156; + gDropdownItemsFormat[3] = 0; + gDropdownItemsFormat[4] = 1156; + gDropdownItemsFormat[5] = 1156; + gDropdownItemsFormat[6] = 1156; + gDropdownItemsFormat[7] = 1156; + gDropdownItemsFormat[8] = 0; + gDropdownItemsFormat[9] = 1156; + gDropdownItemsFormat[10] = 1156; + gDropdownItemsFormat[11] = 1156; + + gDropdownItemsArgs[0] = STR_UNDERGROUND_VIEW; + gDropdownItemsArgs[1] = STR_REMOVE_BASE_LAND; + gDropdownItemsArgs[2] = STR_REMOVE_VERTICAL_FACES; + gDropdownItemsArgs[4] = STR_SEE_THROUGH_RIDES; + gDropdownItemsArgs[5] = STR_SEE_THROUGH_SCENERY; + gDropdownItemsArgs[6] = STR_INVISIBLE_SUPPORTS; + gDropdownItemsArgs[7] = STR_INVISIBLE_PEOPLE; + gDropdownItemsArgs[9] = STR_HEIGHT_MARKS_ON_LAND; + gDropdownItemsArgs[10] = STR_HEIGHT_MARKS_ON_RIDE_TRACKS; + gDropdownItemsArgs[11] = STR_HEIGHT_MARKS_ON_PATHS; + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1] | 0x80, + 0, + 12 + ); + + // Set checkmarks + rct_viewport* mainViewport = window_get_main()->viewport; + if (mainViewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) + gDropdownItemsChecked |= (1 << 0); + if (mainViewport->flags & VIEWPORT_FLAG_HIDE_BASE) + gDropdownItemsChecked |= (1 << 1); + if (mainViewport->flags & VIEWPORT_FLAG_HIDE_VERTICAL) + gDropdownItemsChecked |= (1 << 2); + if (mainViewport->flags & VIEWPORT_FLAG_SEETHROUGH_RIDES) + gDropdownItemsChecked |= (1 << 4); + if (mainViewport->flags & VIEWPORT_FLAG_SEETHROUGH_SCENERY) + gDropdownItemsChecked |= (1 << 5); + if (mainViewport->flags & VIEWPORT_FLAG_INVISIBLE_SUPPORTS) + gDropdownItemsChecked |= (1 << 6); + if (mainViewport->flags & VIEWPORT_FLAG_INVISIBLE_PEEPS) + gDropdownItemsChecked |= (1 << 7); + if (mainViewport->flags & VIEWPORT_FLAG_LAND_HEIGHTS) + gDropdownItemsChecked |= (1 << 9); + if (mainViewport->flags & VIEWPORT_FLAG_TRACK_HEIGHTS) + gDropdownItemsChecked |= (1 << 10); + if (mainViewport->flags & VIEWPORT_FLAG_PATH_HEIGHTS) + gDropdownItemsChecked |= (1 << 11); + + RCT2_GLOBAL(0x9DEBA2, uint16) = 0; +} + +/** + * + * rct2: 0x0066CF8A + */ +void top_toolbar_view_menu_dropdown(short dropdownIndex) { + if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x9DEBA2, uint16); + rct_window* w = window_get_main(); + if (w) { + switch (dropdownIndex) { + case DDIDX_UNDERGROUND_INSIDE: + w->viewport->flags ^= VIEWPORT_FLAG_UNDERGROUND_INSIDE; + break; + case DDIDX_HIDE_BASE: + w->viewport->flags ^= VIEWPORT_FLAG_HIDE_BASE; + break; + case DDIDX_HIDE_VERTICAL: + w->viewport->flags ^= VIEWPORT_FLAG_HIDE_VERTICAL; + break; + case DDIDX_SEETHROUGH_RIDES: + w->viewport->flags ^= VIEWPORT_FLAG_SEETHROUGH_RIDES; + break; + case DDIDX_SEETHROUGH_SCENARY: + w->viewport->flags ^= VIEWPORT_FLAG_SEETHROUGH_SCENERY; + break; + case DDIDX_INVISIBLE_SUPPORTS: + w->viewport->flags ^= VIEWPORT_FLAG_INVISIBLE_SUPPORTS; + break; + case DDIDX_INVISIBLE_PEEPS: + w->viewport->flags ^= VIEWPORT_FLAG_INVISIBLE_PEEPS; + break; + case DDIDX_LAND_HEIGHTS: + w->viewport->flags ^= VIEWPORT_FLAG_LAND_HEIGHTS; + break; + case DDIDX_TRACK_HEIGHTS: + w->viewport->flags ^= VIEWPORT_FLAG_TRACK_HEIGHTS; + break; + case DDIDX_PATH_HEIGHTS: + w->viewport->flags ^= VIEWPORT_FLAG_PATH_HEIGHTS; + break; + default: + return; + } + window_invalidate(w); + } +} + +/** + * + * rct2: 0x0066CCE7 + */ +void toggle_footpath_window() +{ + if (window_find_by_class(WC_FOOTPATH) == NULL) { + window_footpath_open(); + } else { + tool_cancel(); + window_close_by_class(WC_FOOTPATH); + } +} + +/** + * + * rct2: 0x0066CD54 + */ +void toggle_land_window(rct_window *topToolbar, int widgetIndex) +{ + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 7) { + tool_cancel(); + } else { + show_gridlines(); + tool_set(topToolbar, widgetIndex, 18); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + window_land_open(); + } +} + +/** + * + * rct2: 0x0066CD0C + */ +void toggle_clear_scenery_window(rct_window *topToolbar, int widgetIndex) +{ + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 16) { + tool_cancel(); + } else { + show_gridlines(); + tool_set(topToolbar, widgetIndex, 12); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 2; + window_clear_scenery_open(); + } +} + +/** + * + * rct2: 0x0066CD9C + */ +void toggle_water_window(rct_window *topToolbar, int widgetIndex) +{ + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 8) { + tool_cancel(); + } else { + show_gridlines(); + tool_set(topToolbar, widgetIndex, 19); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + window_water_open(); + } +} diff --git a/src/windows/track_list.c b/src/windows/track_list.c index ee5f4a6686..416d6db0e1 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.c @@ -28,6 +28,7 @@ #include "../ride/track.h" #include "../sprites.h" #include "error.h" +#include "../interface/themes.h" enum { WIDX_BACKGROUND, @@ -94,18 +95,6 @@ static void* window_track_list_events[] = { ride_list_item _window_track_list_item; -void window_track_list_format_name(char *dst, const char *src, char colour) -{ - if (colour != 0) - *dst++ = colour; - *dst++ = FORMAT_OPENQUOTES; - while (*src != '.' && *src != 0) { - *dst++ = *src++; - } - *dst++ = FORMAT_ENDQUOTES; - *dst = 0; -} - /** * * rct2: 0x006CF1A2 @@ -126,8 +115,8 @@ void window_track_list_open(ride_list_item item) if (mem == NULL) return; - RCT2_GLOBAL(0x00F44105, void*) = mem; - RCT2_CALLPROC_EBPSAFE(0x006D1DCE); + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*) = mem; + reset_track_list_cache(); if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 300; @@ -136,19 +125,24 @@ void window_track_list_open(ride_list_item item) x = 0; y = 29; } - w = window_create(0, 29, 600, 400, (uint32*)window_track_list_events, WC_TRACK_DESIGN_LIST, 0); + w = window_create( + x, + y, + 600, + 400, + (uint32*)window_track_list_events, + WC_TRACK_DESIGN_LIST, + 0 + ); w->widgets = window_track_list_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_ROTATE) | (1 << WIDX_TOGGLE_SCENERY); window_init_scroll_widgets(w); - w->colours[0] = 26; - w->colours[1] = 26; - w->colours[2] = 26; w->track_list.var_480 = 0xFFFF; - w->track_list.var_482 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 1 : 0; + w->track_list.var_482 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 1; w->track_list.var_484 = 0; - RCT2_GLOBAL(0x00F44152, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) = 0; window_push_others_right(w); - RCT2_GLOBAL(0x00F440AE, uint8) = 2; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = 2; } /** @@ -157,50 +151,52 @@ void window_track_list_open(ride_list_item item) */ static void window_track_list_select(rct_window *w, int index) { - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); rct_track_design *trackDesign; w->track_list.var_480 = index; sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8) && index == 0) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && index == 0) { window_close(w); ride_construct_new(_window_track_list_item); return; } if (RCT2_GLOBAL(0x00F44153, uint8) != 0) - RCT2_GLOBAL(0x00F44152, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) = 1; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8)) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) index--; - trackDesignItem = trackDesignList + (index * 128);; + trackDesignItem = trackDesignList + (index * 128); RCT2_GLOBAL(0x00F4403C, uint8*) = trackDesignItem; window_track_list_format_name( (char*)0x009BC313, trackDesignItem, - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8 ? - 0 : - FORMAT_WHITE - ); + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? + 0 : + FORMAT_WHITE, + 1); - subsitute_path((char*)0x0141EF68, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignItem); + char track_path[MAX_PATH] = { 0 }; + subsitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignItem); - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { window_track_manage_open(); return; } - if (!RCT2_CALLPROC_X(0x0067726A, 0, 0, 0, 0, 0, 0, 0)) { + if (!load_track_design(track_path)) { w->track_list.var_480 = 0xFFFF; window_invalidate(w); return; } trackDesign = track_get_info(index, NULL); - if (trackDesign->var_06 & 4) + if (trackDesign == NULL) return; + if (trackDesign->track_td6.track_flags & 4) window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1); window_close(w); @@ -210,10 +206,10 @@ static void window_track_list_select(rct_window *w, int index) static int window_track_list_get_list_item_index_from_position(int x, int y) { int index; - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); index = 0; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8)) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { y -= 10; if (y < 0) return index; @@ -236,7 +232,7 @@ static int window_track_list_get_list_item_index_from_position(int x, int y) */ static void window_track_list_close() { - free(RCT2_GLOBAL(0x00F44105, void*)); + free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*)); } /** @@ -254,19 +250,19 @@ static void window_track_list_mouseup() case WIDX_CLOSE: window_close(w); if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { - window_close_by_number(WC_47, w->number); - window_close_by_number(WC_48, w->number); + window_close_by_number(WC_MANAGE_TRACK_DESIGN, w->number); + window_close_by_number(WC_TRACK_DELETE_PROMPT, w->number); trackmanager_load(); } break; case WIDX_ROTATE: - RCT2_GLOBAL(0x00F440AE, uint8)++; - RCT2_GLOBAL(0x00F440AE, uint8) %= 4; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8)++; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) %= 4; window_invalidate(w); break; case WIDX_TOGGLE_SCENERY: - RCT2_GLOBAL(0x00F44152, uint8) ^= 1; - RCT2_CALLPROC_EBPSAFE(0x006D1DCE); + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) ^= 1; + reset_track_list_cache(); window_invalidate(w); break; } @@ -279,26 +275,17 @@ static void window_track_list_mouseup() static void window_track_list_scrollgetsize() { rct_window *w; - int height; - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + int width, height; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); window_get_register(w); - height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8 ? 0 : 10; + width = 0; + height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 10; for (trackDesignItem = trackDesignList; *trackDesignItem != 0; trackDesignItem += 128) height += 10; - #ifdef _MSC_VER - __asm mov ecx, 0 - #else - __asm__ ( "mov ecx, 0 " ); - #endif - - #ifdef _MSC_VER - __asm mov edx, height - #else - __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); - #endif + window_scrollsize_set_registers(width, height); } /** @@ -308,14 +295,15 @@ static void window_track_list_scrollgetsize() static void window_track_list_scrollmousedown() { rct_window *w; - short i, x, y; + short i, x, y, scrollIndex; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); if (w->track_list.var_484 & 1) return; - if (RCT2_GLOBAL(0x009DEA6E, uint8) != 0) - return; + // Made it impossible to click a design in pause mode. Since the UI now stays responsive in pause mode, always allow clicking a design. + /*if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) + return;*/ i = window_track_list_get_list_item_index_from_position(x, y); if (i != -1) @@ -329,13 +317,13 @@ static void window_track_list_scrollmousedown() static void window_track_list_scrollmouseover() { rct_window *w; - short i, x, y; + short i, x, y, scrollIndex; - window_scrollmouse_get_registers(w, x, y); + window_scrollmouse_get_registers(w, scrollIndex, x, y); if (w->track_list.var_484 & 1) return; - if (RCT2_GLOBAL(0x009DEA6E, uint8) != 0) + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) return; i = window_track_list_get_list_item_index_from_position(x, y); @@ -365,11 +353,12 @@ static void window_track_list_invalidate() rct_string_id stringId; window_get_register(w); + colour_scheme_update(w); entry = GET_RIDE_ENTRY(_window_track_list_item.entry_index); stringId = entry->name; - if (!(entry->var_008 & 0x1000)) + if (!(entry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME)) stringId = _window_track_list_item.type + 2; RCT2_GLOBAL(0x013CE952, uint16) = stringId; @@ -386,7 +375,7 @@ static void window_track_list_invalidate() w->disabled_widgets &= ~(1 << WIDX_TRACK_PREVIEW); window_track_list_widgets[WIDX_ROTATE].type = WWT_FLATBTN; window_track_list_widgets[WIDX_TOGGLE_SCENERY].type = WWT_FLATBTN; - if (RCT2_GLOBAL(0x00F44152, uint8) == 0) + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) == 0) w->pressed_widgets |= (1 << WIDX_TOGGLE_SCENERY); else w->pressed_widgets &= ~(1 << WIDX_TOGGLE_SCENERY); @@ -407,12 +396,12 @@ static void window_track_list_paint() rct_window *w; rct_drawpixelinfo *dpi; rct_widget *widget; - rct_track_design *trackDesign; - uint8 *image, *trackDesignList = (uint8*)0x00F441EC; + rct_track_design *trackDesign = NULL; + uint8 *image, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); uint16 holes, speed, drops, dropHeight, inversions; fixed32_2dp rating; int trackIndex, x, y, colour, gForces, airTime; - rct_g1_element tmpElement, *subsituteElement, *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); + rct_g1_element tmpElement, *subsituteElement; window_paint_get_registers(w, dpi); @@ -437,6 +426,8 @@ static void window_track_list_paint() if (trackDesign == NULL) return; + rct_track_td6* track_td6 = &trackDesign->track_td6; + subsituteElement = &g1Elements[0]; tmpElement = *subsituteElement; subsituteElement->offset = image; @@ -450,18 +441,18 @@ static void window_track_list_paint() x = w->x + (widget->left + widget->right) / 2; y = w->y + widget->bottom - 12; - + + RCT2_GLOBAL(0x00F44153, uint8) = 0; // Warnings - if ((trackDesign->var_06 & 4) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { + if ((track_td6->track_flags & 4) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { // Vehicle design not available - RCT2_GLOBAL(0x00F44153, uint8) = 0; gfx_draw_string_centred_clipped(dpi, STR_VEHICLE_DESIGN_UNAVAILABLE, NULL, 0, x, y, 368); y -= 10; } - if (trackDesign->var_06 & 1) { + if (track_td6->track_flags & 1) { RCT2_GLOBAL(0x00F44153, uint8) = 1; - if (RCT2_GLOBAL(0x00F44152, uint8) == 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) == 0) { // Scenery not available gfx_draw_string_centred_clipped(dpi, STR_DESIGN_INCLUDES_SCENERY_WHICH_IS_UNAVAILABLE, NULL, 0, x, y, 368); y -= 10; @@ -469,96 +460,97 @@ static void window_track_list_paint() } // Track design name - window_track_list_format_name((char*)0x009BC677, trackDesignList + (trackIndex * 128), FORMAT_WINDOW_COLOUR_1); + window_track_list_format_name((char*)0x009BC677, trackDesignList + (trackIndex * 128), FORMAT_WINDOW_COLOUR_1, 1); gfx_draw_string_centred_clipped(dpi, 3165, NULL, 0, x, y, 368); // Information x = w->x + widget->left + 1; y = w->y + widget->bottom + 2; - if (trackDesign->var_6C & 0x80000000) { + if (track_td6->var_6C & 0x80000000) { // Six flags logo gfx_draw_sprite(dpi, SPR_SIX_FLAGS, w->x + widget->right - 50, y + 4, 0); } // Stats - rating = trackDesign->excitement * 10; + rating = track_td6->excitement * 10; gfx_draw_string_left(dpi, STR_TRACK_LIST_EXCITEMENT_RATING, &rating, 0, x, y); y += 10; - rating = trackDesign->intensity * 10; + rating = track_td6->intensity * 10; gfx_draw_string_left(dpi, STR_TRACK_LIST_INTENSITY_RATING, &rating, 0, x, y); y += 10; - rating = trackDesign->nausea * 10; + rating = track_td6->nausea * 10; gfx_draw_string_left(dpi, STR_TRACK_LIST_NAUSEA_RATING, &rating, 0, x, y); y += 14; - if (trackDesign->type != RIDE_TYPE_MAZE) { - if (trackDesign->type == RIDE_TYPE_MINI_GOLF) { + if (track_td6->type != RIDE_TYPE_MAZE) { + if (track_td6->type == RIDE_TYPE_MINI_GOLF) { // Holes - holes = trackDesign->holes & 0x1F; + holes = track_td6->holes & 0x1F; gfx_draw_string_left(dpi, STR_HOLES, &holes, 0, x, y); y += 10; } else { // Maximum speed - speed = ((trackDesign->max_speed << 16) * 9) >> 18; + speed = ((track_td6->max_speed << 16) * 9) >> 18; gfx_draw_string_left(dpi, STR_MAX_SPEED, &speed, 0, x, y); y += 10; // Average speed - speed = ((trackDesign->average_speed << 16) * 9) >> 18; + speed = ((track_td6->average_speed << 16) * 9) >> 18; gfx_draw_string_left(dpi, STR_AVERAGE_SPEED, &speed, 0, x, y); y += 10; } // Ride length RCT2_GLOBAL(0x013CE952 + 0, uint16) = 1345; - RCT2_GLOBAL(0x013CE952 + 2, uint16) = trackDesign->ride_length; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = track_td6->ride_length; gfx_draw_string_left_clipped(dpi, STR_TRACK_LIST_RIDE_LENGTH, (void*)0x013CE952, 0, x, y, 214); y += 10; } - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (trackDesign->type * 8), uint32) & 0x80) { + if (ride_type_has_flag(track_td6->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) { // Maximum positive vertical Gs - gForces = trackDesign->max_positive_vertical_g * 32; + gForces = track_td6->max_positive_vertical_g * 32; gfx_draw_string_left(dpi, STR_MAX_POSITIVE_VERTICAL_G, &gForces, 0, x, y); y += 10; // Maximum negative verical Gs - gForces = trackDesign->max_negitive_vertical_g * 32; + gForces = track_td6->max_negative_vertical_g * 32; gfx_draw_string_left(dpi, STR_MAX_NEGATIVE_VERTICAL_G, &gForces, 0, x, y); y += 10; // Maximum lateral Gs - gForces = trackDesign->max_lateral_g * 32; + gForces = track_td6->max_lateral_g * 32; gfx_draw_string_left(dpi, STR_MAX_LATERAL_G, &gForces, 0, x, y); y += 10; - if (trackDesign->var_07 / 4 >= 2) { - if (trackDesign->total_air_time != 0) { + // If .TD6 + if (track_td6->version_and_colour_scheme / 4 >= 2) { + if (track_td6->total_air_time != 0) { // Total air time - airTime = trackDesign->total_air_time * 25; + airTime = track_td6->total_air_time * 25; gfx_draw_string_left(dpi, STR_TOTAL_AIR_TIME, &airTime, 0, x, y); y += 10; } } } - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (trackDesign->type * 8), uint32) & 0x400) { + if (ride_type_has_flag(track_td6->type, RIDE_TYPE_FLAG_HAS_DROPS)) { // Drops - drops = trackDesign->drops & 0x3F; + drops = track_td6->drops & 0x3F; gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y); y += 10; // Drop height is multiplied by 0.75 - dropHeight = (trackDesign->highest_drop_height + (trackDesign->highest_drop_height / 2)) / 2; + dropHeight = (track_td6->highest_drop_height + (track_td6->highest_drop_height / 2)) / 2; gfx_draw_string_left(dpi, STR_HIGHEST_DROP_HEIGHT, &drops, 0, x, y); y += 10; } - if (trackDesign->type != RIDE_TYPE_MINI_GOLF) { - inversions = trackDesign->inversions & 0x1F; + if (track_td6->type != RIDE_TYPE_MINI_GOLF) { + inversions = track_td6->inversions & 0x1F; if (inversions != 0) { // Inversions gfx_draw_string_left(dpi, STR_INVERSIONS, &inversions, 0, x, y); @@ -567,16 +559,16 @@ static void window_track_list_paint() } y += 4; - if (trackDesign->space_required_x != 0xFF) { + if (track_td6->space_required_x != 0xFF) { // Space required - RCT2_GLOBAL(0x013CE952 + 0, uint16) = trackDesign->space_required_x; - RCT2_GLOBAL(0x013CE952 + 2, uint16) = trackDesign->space_required_y; + RCT2_GLOBAL(0x013CE952 + 0, uint16) = track_td6->space_required_x; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = track_td6->space_required_y; gfx_draw_string_left(dpi, STR_TRACK_LIST_SPACE_REQUIRED, (void*)0x013CE952, 0, x, y); y += 10; } - if (trackDesign->cost != 0) { - gfx_draw_string_left(dpi, STR_TRACK_LIST_COST_AROUND, &trackDesign->cost, 0, x, y); + if (track_td6->cost != 0) { + gfx_draw_string_left(dpi, STR_TRACK_LIST_COST_AROUND, &track_td6->cost, 0, x, y); y += 14; } } @@ -591,7 +583,7 @@ static void window_track_list_scrollpaint() rct_drawpixelinfo *dpi; rct_string_id stringId, stringId2; int i, x, y, colour; - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); window_paint_get_registers(w, dpi); @@ -623,9 +615,9 @@ static void window_track_list_scrollpaint() stringId2 = STR_BUILD_CUSTOM_DESIGN; gfx_draw_string_left(dpi, stringId, &stringId2, 0, x, y - 1); y += 10; + i++; } - i++; while (*trackDesignItem != 0) { if (y + 10 >= dpi->y && y < dpi->y + dpi->height) { if (i == w->track_list.var_482) { @@ -637,7 +629,7 @@ static void window_track_list_scrollpaint() } // Draw track name - window_track_list_format_name((char*)0x009BC678, trackDesignItem, 0); + window_track_list_format_name((char *)language_get_string(3165), trackDesignItem, 0, 1); stringId2 = 3165; gfx_draw_string_left(dpi, stringId, &stringId2, 0, x, y - 1); } @@ -645,4 +637,4 @@ static void window_track_list_scrollpaint() i++; trackDesignItem += 128; } -} \ No newline at end of file +} diff --git a/src/windows/track_manage.c b/src/windows/track_manage.c index ebfe54d6c6..9f9bea901f 100644 --- a/src/windows/track_manage.c +++ b/src/windows/track_manage.c @@ -19,7 +19,129 @@ *****************************************************************************/ #include "../addresses.h" +#include "../interface/widget.h" #include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../ride/track.h" +#include "error.h" +#include "../interface/themes.h" + +#pragma region Widgets + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_RENAME, + WIDX_DELETE, + + WIDX_PROMPT_DELETE = 3, + WIDX_PROMPT_CANCEL = 4, +}; + +static rct_widget window_track_manage_widgets[] = { + { WWT_FRAME, 0, 0, 249, 0, 43, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 248, 1, 14, 3155, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 237, 247, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 10, 119, 24, 35, STR_TRACK_MANAGE_RENAME, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 0, 130, 239, 24, 35, STR_TRACK_MANAGE_DELETE, STR_NONE }, + { WIDGETS_END } +}; + +static rct_widget window_track_delete_prompt_widgets[] = { + { WWT_FRAME, 0, 0, 249, 0, 73, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 248, 1, 14, 3356, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 237, 247, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 10, 119, 54, 65, 3349, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 0, 130, 239, 54, 65, 972, STR_NONE }, + { WIDGETS_END } +}; + +#pragma endregion + +#pragma region Events + +static void window_track_manage_emptysub() { } + +static void window_track_manage_close(); +static void window_track_manage_mouseup(); +static void window_track_manage_textinput(); +static void window_track_manage_invalidate(); +static void window_track_manage_paint(); + +static void window_track_delete_prompt_emptysub() { } + +static void window_track_delete_prompt_mouseup(); +static void window_track_delete_prompt_invalidate(); +static void window_track_delete_prompt_paint(); + +// 0x009940EC +static void* window_track_manage_events[] = { + window_track_manage_close, + window_track_manage_mouseup, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_textinput, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_emptysub, + window_track_manage_invalidate, + window_track_manage_paint, + window_track_manage_emptysub +}; + +// 0x0099415C +static void* window_track_delete_prompt_events[] = { + window_track_delete_prompt_emptysub, + window_track_delete_prompt_mouseup, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_emptysub, + window_track_delete_prompt_invalidate, + window_track_delete_prompt_paint, + window_track_delete_prompt_emptysub +}; + +#pragma endregion + +static void window_track_delete_prompt_open(); /** * @@ -27,5 +149,200 @@ */ void window_track_manage_open() { - RCT2_CALLPROC_EBPSAFE(0x006D348F); + rct_window *w, *trackDesignListWindow; + + window_close_by_class(WC_MANAGE_TRACK_DESIGN); + + w = window_create_centred( + 250, + 44, + (uint32*)window_track_manage_events, + WC_MANAGE_TRACK_DESIGN, + WF_STICK_TO_FRONT | WF_TRANSPARENT + ); + w->widgets = window_track_manage_widgets; + w->enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_RENAME) | + (1 << WIDX_DELETE); + window_init_scroll_widgets(w); + + trackDesignListWindow = window_find_by_class(WC_TRACK_DESIGN_LIST); + if (trackDesignListWindow != NULL) + trackDesignListWindow->track_list.var_484 |= 1; +} + +/** + * + * rct2: 0x006D364C + */ +static void window_track_manage_close() +{ + rct_window *w; + + w = window_find_by_class(WC_TRACK_DESIGN_LIST); + if (w != NULL) + w->track_list.var_484 &= ~1; +} + +/** + * + * rct2: 0x006D3523 + */ +static void window_track_manage_mouseup() +{ + uint8 *trackDesignList = (uint8*)0x00F441EC; + rct_window *w, *trackDesignListWindow; + short widgetIndex; + char *dst, *src; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_RENAME: + trackDesignListWindow = window_find_by_class(WC_TRACK_DESIGN_LIST); + if (trackDesignListWindow != NULL) { + src = &trackDesignList[trackDesignListWindow->track_list.var_482 * 128]; + dst = (char*)0x009BC677; + while (*src != 0 && *src != '.') + *dst++ = *src++; + *dst = 0; + window_text_input_open(w, widgetIndex, 3350, 3351, 3165, 0, 127); + } + break; + case WIDX_DELETE: + window_track_delete_prompt_open(); + break; + } +} + +/** + * + * rct2: 0x006D3523 + */ +static void window_track_manage_textinput() +{ + rct_window *w; + short widgetIndex; + uint8 result; + char *text; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (widgetIndex != WIDX_RENAME || !result) + return; + + if (track_rename(text)) { + window_close_by_class(WC_TRACK_DELETE_PROMPT); + window_close(w); + } else { + window_error_open(STR_CANT_RENAME_TRACK_DESIGN, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16)); + } +} + +static void window_track_manage_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + +/** + * + * rct2: 0x006D3523 + */ +static void window_track_manage_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); +} + +/** + * + * rct2: 0x006D35CD + */ +static void window_track_delete_prompt_open() +{ + rct_window *w; + + window_close_by_class(WC_TRACK_DELETE_PROMPT); + + w = window_create( + max(28, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 250) / 2), + (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 44) / 2, + 250, + 74, + (uint32*)window_track_delete_prompt_events, + WC_TRACK_DELETE_PROMPT, + WF_STICK_TO_FRONT + ); + w->widgets = window_track_delete_prompt_widgets; + w->enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_RENAME) | + (1 << WIDX_DELETE); + window_init_scroll_widgets(w); + w->flags |= WF_TRANSPARENT; +} + +/** + * + * rct2: 0x006D3823 + */ +static void window_track_delete_prompt_mouseup() +{ + rct_window *w; + short widgetIndex; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + case WIDX_PROMPT_CANCEL: + window_close(w); + break; + case WIDX_PROMPT_DELETE: + window_close(w); + if (track_delete()) + window_close_by_class(WC_MANAGE_TRACK_DESIGN); + else + window_error_open(STR_CANT_DELETE_TRACK_DESIGN, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16)); + break; + } +} + +static void window_track_delete_prompt_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + +/** + * + * rct2: 0x006D37EE + */ +static void window_track_delete_prompt_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_string_id stringId; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + stringId = 3155; + gfx_draw_string_centred_wrapped( + dpi, &stringId, w->x + 125, w->y + 28, 246, STR_ARE_YOU_SURE_YOU_WANT_TO_PERMANENTLY_DELETE_TRACK, 0 + ); } \ No newline at end of file diff --git a/src/windows/track_place.c b/src/windows/track_place.c index e5e586f2d1..7e8bcbf35f 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -28,6 +28,8 @@ #include "../localisation/localisation.h" #include "../sprites.h" #include "../ride/track.h" +#include "../ride/track_data.h" +#include "../interface/themes.h" #define TRACK_MINI_PREVIEW_WIDTH 168 #define TRACK_MINI_PREVIEW_HEIGHT 78 @@ -62,6 +64,7 @@ static void window_track_place_toolupdate(); static void window_track_place_tooldown(); static void window_track_place_toolabort(); static void window_track_place_unknown14(); +static void window_track_place_invalidate(); static void window_track_place_paint(); static void* window_track_place_events[] = { @@ -90,7 +93,7 @@ static void* window_track_place_events[] = { window_track_place_emptysub, window_track_place_emptysub, window_track_place_emptysub, - window_track_place_emptysub, + window_track_place_invalidate, window_track_place_paint, window_track_place_emptysub }; @@ -114,33 +117,6 @@ static void window_track_place_clear_mini_preview() memset(_window_track_place_mini_preview, 220, TRACK_MINI_PREVIEW_SIZE); } -/** - * Size: 0x0A - */ -typedef struct { - uint8 var_00; - sint16 x; - sint16 y; - uint8 pad_05[3]; - uint8 var_08; - uint8 unk_09; -} rct_preview_track; - -/** - * Size: 0x04 - */ -typedef struct { - union { - uint32 all; - struct { - sint8 x; - sint8 y; - uint8 unk_2; - uint8 type; - }; - }; -} rct_preview_maze; - #define swap(x, y) x = x ^ y; y = x ^ y; x = x ^ y; /** @@ -149,10 +125,11 @@ typedef struct { */ static void window_track_place_draw_mini_preview() { - rct_track_design *design = (rct_track_design*)0x009D8178; - uint8 *pixel, colour, *trackPtr, bits; + rct_track_td6 *track = RCT2_ADDRESS(0x009D8178, rct_track_td6); + uint8 *pixel, colour, bits; int i, rotation, pass, x, y, pixelX, pixelY, originX, originY, minX, minY, maxX, maxY; - rct_preview_maze *mazeBlock; + rct_maze_element *mazeElement; + rct_track_element *trackElement; rct_preview_track *trackBlock; window_track_place_clear_mini_preview(); @@ -171,14 +148,14 @@ static void window_track_place_draw_mini_preview() originY -= ((maxY + minY) >> 6) << 5; } - if (design->type != RIDE_TYPE_MAZE) { + if (track->type != RIDE_TYPE_MAZE) { #pragma region Track - rotation = RCT2_GLOBAL(0x00F440AE, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); - trackPtr = design->preview[0]; + rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + trackElement = RCT2_ADDRESS(0x009D821B, rct_track_element); - while (*trackPtr != 255) { - int trackType = *trackPtr; + while (trackElement->type != 255) { + int trackType = trackElement->type; if (trackType == 101) trackType = 255; @@ -218,7 +195,7 @@ static void window_track_place_draw_mini_preview() } else { pixelX = 80 + ((y / 32) - (x / 32)) * 4; pixelY = 38 + ((y / 32) + (x / 32)) * 2; - if (pixelX <= 160 && pixelY <= 75) { + if (pixelX >= 0 && pixelY >= 0 && pixelX <= 160 && pixelY <= 75) { pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; bits = trackBlock->var_08 << (rotation & 3); @@ -237,45 +214,47 @@ static void window_track_place_draw_mini_preview() // Change rotation and next position based on track curvature rotation &= 3; + const rct_track_coordinates* track_coordinate = &TrackCoordinates[trackType]; + trackType *= 10; switch (rotation) { case 0: - originX += RCT2_GLOBAL(0x009968C1 + trackType, sint16); - originY += RCT2_GLOBAL(0x009968C3 + trackType, sint16); + originX += track_coordinate->x; + originY += track_coordinate->y; break; case 1: - originX += RCT2_GLOBAL(0x009968C3 + trackType, sint16); - originY -= RCT2_GLOBAL(0x009968C1 + trackType, sint16); + originX += track_coordinate->y; + originY -= track_coordinate->x; break; case 2: - originX -= RCT2_GLOBAL(0x009968C1 + trackType, sint16); - originY -= RCT2_GLOBAL(0x009968C3 + trackType, sint16); + originX -= track_coordinate->x; + originY -= track_coordinate->y; break; case 3: - originX -= RCT2_GLOBAL(0x009968C3 + trackType, sint16); - originY += RCT2_GLOBAL(0x009968C1 + trackType, sint16); + originX -= track_coordinate->y; + originY += track_coordinate->x; break; } - rotation += RCT2_ADDRESS(0x009968BC, uint8)[trackType] - RCT2_ADDRESS(0x009968BB, uint8)[trackType]; + rotation += track_coordinate->rotation_positive - track_coordinate->rotation_negative; rotation &= 3; - if (RCT2_ADDRESS(0x009968BC, uint8)[trackType] & 4) + if (track_coordinate->rotation_positive & 4) rotation |= 4; if (!(rotation & 4)) { originX += RCT2_GLOBAL(0x00993CCC + (rotation * 4), sint16); originY += RCT2_GLOBAL(0x00993CCE + (rotation * 4), sint16); } - trackPtr += 2; + trackElement++; } #pragma endregion } else { #pragma region Maze - rotation = (RCT2_GLOBAL(0x00F440AE, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) & 3; - mazeBlock = (rct_preview_maze*)design->preview[0]; - while (mazeBlock->all != 0) { - x = mazeBlock->x * 32; - y = mazeBlock->y * 32; + rotation = (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) & 3; + mazeElement = RCT2_ADDRESS(0x009D821B, rct_maze_element); + while (mazeElement->all != 0) { + x = mazeElement->x * 32; + y = mazeElement->y * 32; switch (rotation) { case 1: x = -x; @@ -294,7 +273,7 @@ static void window_track_place_draw_mini_preview() y += originY; // Entrance or exit is a lighter colour - colour = mazeBlock->type == 8 || mazeBlock->type == 128 ? 222 : 218; + colour = mazeElement->type == 8 || mazeElement->type == 128 ? 222 : 218; if (pass == 0) { minX = min(minX, x); @@ -315,7 +294,7 @@ static void window_track_place_draw_mini_preview() } } } - mazeBlock++; + mazeElement++; } #pragma endregion @@ -323,38 +302,6 @@ static void window_track_place_draw_mini_preview() } } -/** - * - * rct2: 0x0068A15E - */ -static void sub_68A15E(int x, int y, short *ax, short *bx) -{ - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ebx = y; - RCT2_CALLFUNC_X(0x0068A15E, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *ax = *((short*)&eax); - *bx = *((short*)&ebx); -} - -/** - * Seems to highlight the surface tiles to match the track layout at the given position but also returns some Z value. - * rct2: 0x006D01B3 - */ -static int sub_6D01B3(int bl, int x, int y, int z) -{ - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ebx = bl; - ecx = y; - edx = z; - esi = 0; - edi = 0; - ebp = 0; - RCT2_CALLFUNC_X(0x006D01B3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return *((short*)&ebx); -} - /** * * rct2: 0x006D017F @@ -363,7 +310,8 @@ static void window_track_place_clear_provisional() { if (_window_track_place_last_was_valid) { sub_6D01B3( - (RCT2_GLOBAL(0x00F440EB, uint8) << 8) | 6, + 6, + RCT2_GLOBAL(0x00F440EB, uint8), _window_track_place_last_valid_x, _window_track_place_last_valid_y, _window_track_place_last_valid_z @@ -397,7 +345,7 @@ static int window_track_place_get_base_z(int x, int y) if (mapElement->properties.surface.terrain & 0x1F) z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4); - return z + sub_6D01B3(3, x, y, z); + return z + sub_6D01B3(3, 0, x, y, z); } static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex) @@ -409,7 +357,7 @@ static void window_track_place_attempt_placement(int x, int y, int z, int bl, mo ebx = bl; ecx = y; edi = z; - result = game_do_command_p(GAME_COMMAND_47, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + result = game_do_command_p(GAME_COMMAND_PLACE_TRACK, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); if (cost != NULL) *cost = result; if (rideIndex != NULL) *rideIndex = edi & 0xFF; @@ -428,20 +376,25 @@ void window_track_place_open() _window_track_place_mini_preview = malloc(TRACK_MINI_PREVIEW_SIZE); window_track_place_clear_mini_preview(); - w = window_create(0, 29, 200, 124, (uint32*)window_track_place_events, WC_TRACK_DESIGN_PLACE, 0); + w = window_create( + 0, + 29, + 200, + 124, + (uint32*)window_track_place_events, + WC_TRACK_DESIGN_PLACE, + 0 + ); w->widgets = window_track_place_widgets; w->enabled_widgets = 4 | 8 | 0x10 | 0x20; window_init_scroll_widgets(w); - w->colours[0] = 24; - w->colours[1] = 24; - w->colours[2] = 24; tool_set(w, 6, 12); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= 6; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; window_push_others_right(w); show_gridlines(); _window_track_place_last_cost = MONEY32_UNDEFINED; _window_track_place_last_x = 0xFFFF; - RCT2_GLOBAL(0x00F440AE, uint8) = (-RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = (-RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3; window_track_place_draw_mini_preview(); } @@ -453,7 +406,7 @@ static void window_track_place_close() { window_track_place_clear_provisional(); viewport_set_visibility(0); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~6; hide_gridlines(); free(_window_track_place_mini_preview); @@ -476,14 +429,14 @@ static void window_track_place_mouseup() break; case WIDX_ROTATE: window_track_place_clear_provisional(); - RCT2_GLOBAL(0x00F440AE, uint16) = (RCT2_GLOBAL(0x00F440AE, uint16) + 1) & 3; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint16) = (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint16) + 1) & 3; window_invalidate(w); _window_track_place_last_x = 0xFFFF; window_track_place_draw_mini_preview(); break; case WIDX_MIRROR: - RCT2_CALLPROC_EBPSAFE(0x006D2436); - RCT2_GLOBAL(0x00F440AE, uint16) = (-RCT2_GLOBAL(0x00F440AE, uint16)) & 3; + track_mirror(); + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint16) = (-RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint16)) & 3; window_invalidate(w); _window_track_place_last_x = 0xFFFF; window_track_place_draw_mini_preview(); @@ -520,11 +473,11 @@ static void window_track_place_toolupdate() window_tool_get_registers(w, widgetIndex, x, y); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; // Get the tool map position - sub_68A15E(x, y, &x, &y); + sub_68A15E(x, y, &x, &y, NULL, NULL); if (x == (short)0x8000) { window_track_place_clear_provisional(); return; @@ -532,7 +485,7 @@ static void window_track_place_toolupdate() // Check if tool map position has changed since last update if (x == _window_track_place_last_x && y == _window_track_place_last_y) { - sub_6D01B3(0, x, y, 0); + sub_6D01B3(0, 0, x, y, 0); return; } @@ -540,7 +493,7 @@ static void window_track_place_toolupdate() // Get base Z position z = window_track_place_get_base_z(x, y); - if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0 || gConfigCheat.build_in_pause_mode) { window_track_place_clear_provisional(); // Try increasing Z until a feasible placement is found @@ -565,7 +518,7 @@ static void window_track_place_toolupdate() widget_invalidate(w, WIDX_PRICE); } - sub_6D01B3(0, x, y, z); + sub_6D01B3(0, 0, x, y, z); } /** @@ -583,10 +536,10 @@ static void window_track_place_tooldown() window_tool_get_registers(w, widgetIndex, x, y); window_track_place_clear_provisional(); - RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; - sub_68A15E(x, y, &x, &y); + sub_68A15E(x, y, &x, &y, NULL, NULL); if (x == (short)0x8000) return; @@ -642,6 +595,14 @@ static void window_track_place_unknown14() window_track_place_draw_mini_preview(); } +static void window_track_place_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); +} + /** * * rct2: 0x006CFD9D @@ -650,7 +611,7 @@ static void window_track_place_paint() { rct_window *w; rct_drawpixelinfo *dpi, *clippedDpi; - rct_g1_element tmpElement, *subsituteElement, *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); + rct_g1_element tmpElement, *subsituteElement; window_paint_get_registers(w, dpi); @@ -669,10 +630,12 @@ static void window_track_place_paint() subsituteElement->flags = 0; gfx_draw_sprite(clippedDpi, 0, 0, 0, 0); *subsituteElement = tmpElement; + + rct2_free(clippedDpi); } // Price if (_window_track_place_last_cost != MONEY32_UNDEFINED) if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, &_window_track_place_last_cost); -} \ No newline at end of file +} diff --git a/src/windows/viewport.c b/src/windows/viewport.c index 924926ad1b..c40ea69850 100644 --- a/src/windows/viewport.c +++ b/src/windows/viewport.c @@ -28,6 +28,7 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "dropdown.h" +#include "../interface/themes.h" #define INITIAL_WIDTH 500 #define INITIAL_HEIGHT 350 @@ -44,15 +45,15 @@ enum { }; static rct_widget window_viewport_widgets[] = { - { WWT_FRAME, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 0, 1, 14, 2779, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 0, 0, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_RESIZE, 1, 0, 0, 14, 0, 0xFFFFFFFF, STR_NONE }, // resize - { WWT_VIEWPORT, 0, 3, 0, 17, 0, 0xFFFFFFFF, STR_NONE }, // viewport + { WWT_FRAME, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 0, 1, 14, 2779, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 0, 0, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_RESIZE, 1, 0, 0, 14, 0, 0xFFFFFFFF, STR_NONE }, // resize + { WWT_VIEWPORT, 0, 3, 0, 17, 0, 0xFFFFFFFF, STR_NONE }, // viewport - { WWT_FLATBTN, 0, 0, 0, 17, 40, 0xFFFFFFFF, STR_ZOOM_IN_TIP }, // zoom in - { WWT_FLATBTN, 0, 0, 0, 41, 64, 0xFFFFFFFF, STR_ZOOM_OUT_TIP }, // zoom out - { WWT_FLATBTN, 0, 0, 0, 65, 88, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, // locate + { WWT_FLATBTN, 0, 0, 0, 17, 40, SPR_G2_ZOOM_IN, STR_ZOOM_IN_TIP }, // zoom in + { WWT_FLATBTN, 0, 0, 0, 41, 64, SPR_G2_ZOOM_OUT, STR_ZOOM_OUT_TIP }, // zoom out + { WWT_FLATBTN, 0, 0, 0, 65, 88, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, // locate { WIDGETS_END }, }; @@ -118,9 +119,6 @@ void window_viewport_open() (1 << WIDX_ZOOM_OUT) | (1 << WIDX_LOCATE); w->number = _viewportNumber++; - w->colours[0] = 24; - w->colours[1] = 24; - w->colours[2] = 24; rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32); @@ -153,7 +151,7 @@ static void window_viewport_mouseup() { short widgetIndex; rct_window *w, *mainWindow; - int x, y; + sint16 x, y; window_widget_get_registers(w, widgetIndex); @@ -176,7 +174,7 @@ static void window_viewport_mouseup() case WIDX_LOCATE: mainWindow = window_get_main(); if (mainWindow != NULL) { - get_map_coordinates_from_pos(w->x + (w->width / 2), w->y + (w->height / 2), 0, &x, &y, NULL, NULL); + get_map_coordinates_from_pos(w->x + (w->width / 2), w->y + (w->height / 2), VIEWPORT_INTERACTION_MASK_NONE, &x, &y, NULL, NULL, NULL); window_scroll_to_location(mainWindow, x, y, map_element_height(x, y)); } break; @@ -218,6 +216,7 @@ static void window_viewport_invalidate() int i; window_get_register(w); + colour_scheme_update(w); viewportWidget = &window_viewport_widgets[WIDX_VIEWPORT]; viewport = w->viewport; diff --git a/src/windows/water.c b/src/windows/water.c index 5e0ce4bac9..ff74724149 100644 --- a/src/windows/water.c +++ b/src/windows/water.c @@ -25,6 +25,7 @@ #include "../localisation/localisation.h" #include "../sprites.h" #include "../world/map.h" +#include "../interface/themes.h" enum WINDOW_WATER_WIDGET_IDX { WIDX_BACKGROUND, @@ -53,6 +54,8 @@ static void window_water_mouseup(); static void window_water_update(); static void window_water_invalidate(); static void window_water_paint(); +static void window_water_textinput(); +static void window_water_inputsize(rct_window *w); static void* window_water_events[] = { window_water_close, @@ -74,7 +77,7 @@ static void* window_water_events[] = { window_water_emptysub, window_water_emptysub, window_water_emptysub, - window_water_emptysub, + window_water_textinput, window_water_emptysub, window_water_emptysub, window_water_emptysub, @@ -97,17 +100,22 @@ void window_water_open() if (window_find_by_class(WC_WATER) != NULL) return; - window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 76, 29, 76, 77, (uint32*)window_water_events, WC_WATER, 0); + window = window_create( + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 76, + 29, + 76, + 77, + (uint32*)window_water_events, + WC_WATER, + 0 + ); window->widgets = window_water_widgets; - window->enabled_widgets = 0x04 | 0x10 | 0x20; + window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_DECREMENT) | (1 << WIDX_INCREMENT) | (1 << WIDX_PREVIEW); window_init_scroll_widgets(window); window_push_others_below(window); RCT2_GLOBAL(RCT2_ADDRESS_WATER_RAISE_COST, uint32) = MONEY32_UNDEFINED; RCT2_GLOBAL(RCT2_ADDRESS_WATER_LOWER_COST, uint32) = MONEY32_UNDEFINED; - window->colours[0] = 24; - window->colours[1] = 24; - window->colours[2] = 24; } /** @@ -162,9 +170,42 @@ static void window_water_mouseup() // Invalidate the window window_invalidate(w); break; + case WIDX_PREVIEW: + window_water_inputsize(w); + break; } } +static void window_water_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + int size; + char* end; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (widgetIndex != WIDX_PREVIEW || !result) + return; + + size = strtol(text, &end, 10); + if (*end == '\0') { + if (size < 1) size = 1; + if (size > 64) size = 64; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = size; + window_invalidate(w); + } +} + +static void window_water_inputsize(rct_window *w) +{ + ((uint16*)TextInputDescriptionArgs)[0] = 1; + ((uint16*)TextInputDescriptionArgs)[1] = 64; + window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); +} + /** * * rct2: 0x006E6BCE @@ -185,6 +226,7 @@ static void window_water_invalidate() rct_window *w; window_get_register(w); + colour_scheme_update(w); // Set the preview image button to be pressed down w->pressed_widgets |= (1 << WIDX_PREVIEW); diff --git a/src/world/banner.c b/src/world/banner.c index 9a957a83b1..306b1cad26 100644 --- a/src/world/banner.c +++ b/src/world/banner.c @@ -19,6 +19,49 @@ *****************************************************************************/ #include "../addresses.h" +#include "../game.h" +#include "../localisation/localisation.h" #include "banner.h" -rct_banner *gBanners = (rct_banner*)0x0135A124; \ No newline at end of file +rct_banner *gBanners = (rct_banner*)0x0135A124; + +/** + * + * rct2: 0x006B9CB0 + */ +void banner_init() { + for(int i = 0; i < MAX_BANNERS; i++) { + gBanners[i].type = BANNER_NULL; + } +} + +/* rct2: 0x006BA278 + * Creates a new banner and returns the index of the banner + * If the flag GAME_COMMAND_FLAG_APPLY is NOT set then returns + * the first unused index but does NOT mark the banner as created. + * returns 0xFF on failure. + */ +int create_new_banner(uint8 flags){ + int banner_index = 0; + for (; banner_index < MAX_BANNERS; banner_index++){ + if (gBanners[banner_index].type == BANNER_NULL){ + break; + } + } + + if (banner_index == MAX_BANNERS){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_MANY_BANNERS_IN_GAME; + return BANNER_NULL; + } + + if (flags & GAME_COMMAND_FLAG_APPLY){ + rct_banner* banner = &gBanners[banner_index]; + + banner->flags = 0; + banner->type = 0; + banner->string_idx = 778; + banner->colour = 2; + banner->text_colour = 2; + } + return banner_index; +} \ No newline at end of file diff --git a/src/world/banner.h b/src/world/banner.h index 8496a132a1..3944fd7c9c 100644 --- a/src/world/banner.h +++ b/src/world/banner.h @@ -23,6 +23,7 @@ #include "../common.h" +#define BANNER_NULL 255 #define MAX_BANNERS 250 typedef struct { @@ -37,9 +38,13 @@ typedef struct { enum{ BANNER_FLAG_NO_ENTRY = (1 << 0), + BANNER_FLAG_1 = (1 << 1), BANNER_FLAG_2 = (1 << 2) } BANNER_FLAGS; extern rct_banner *gBanners; +void banner_init(); +int create_new_banner(uint8 flags); + #endif diff --git a/src/world/climate.c b/src/world/climate.c index c56a1a5b88..79e231c2da 100644 --- a/src/world/climate.c +++ b/src/world/climate.c @@ -24,6 +24,7 @@ #include "../drawing/drawing.h" #include "../localisation/date.h" #include "../scenario.h" +#include "../interface/window.h" #include "climate.h" enum { @@ -39,14 +40,22 @@ typedef struct { sint8 distribution[24]; } rct_weather_transition; -int gClimateNextWeather; +// These still need to be read / written when loading and saving +// int gClimateNextWeather; +// +// static int _climateCurrentWeatherEffect; +// +// static int _climateNextTemperature; +// static int _climateNextWeatherEffect; +// static int _climateNextWeatherGloom; +// static int _climateNextRainLevel; -static int _climateCurrentWeatherEffect; +#define _climateCurrentWeatherEffect RCT2_GLOBAL(0x013CA74E, uint8) -static int _climateNextTemperature; -static int _climateNextWeatherEffect; -static int _climateNextWeatherGloom; -static int _climateNextRainLevel; +#define _climateNextTemperature RCT2_GLOBAL(0x013CA74D, uint8) +#define _climateNextWeatherEffect RCT2_GLOBAL(0x013CA74F, uint8) +#define _climateNextWeatherGloom RCT2_GLOBAL(0x013CA751, uint8) +#define _climateNextRainLevel RCT2_GLOBAL(0x013CA753, uint8) static const rct_weather_transition* climate_transitions[4]; @@ -75,6 +84,10 @@ int climate_celsius_to_fahrenheit(int celsius) return (celsius * 29) / 16 + 32; } +// cheats +extern int g_climate_locked; +extern void toggle_climate_lock(); + /** * Set climate and determine start weather. * rct2: 0x006C45ED @@ -92,6 +105,20 @@ void climate_reset(int climate) RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_EFFECT, sint8) = climate_weather_data[weather].effect_level; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_GLOOM, sint8) = climate_weather_data[weather].gloom_level; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, sint8) = climate_weather_data[weather].rain_level; + + _lightningTimer = 0; + _thunderTimer = 0; + if (_rainVolume != 1){ +#ifdef USE_MIXER + if (_rainSoundChannel) { + Mixer_Stop_Channel(_rainSoundChannel); + _rainSoundChannel = 0; + } +#else + sound_stop(&_rainSoundInstance); +#endif + _rainVolume = 1; + } climate_determine_future_weather(); } @@ -136,7 +163,7 @@ void climate_update() if (RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE_UPDATE_TIMER, sint16)) { if (RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE_UPDATE_TIMER, sint16) == 960) - RCT2_GLOBAL(0x009A9804, uint32) |= 8; // climate dirty flag? + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint32) |= BTM_TB_DIRTY_FLAG_CLIMATE; RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE_UPDATE_TIMER, sint16)--; @@ -145,11 +172,13 @@ void climate_update() if (temperature == target_temperature) { if (cur_gloom == next_gloom) { _climateCurrentWeatherEffect = _climateNextWeatherEffect; + _thunderTimer = 0; + _lightningTimer = 0; if (cur_rain == next_rain) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER, sint8) = gClimateNextWeather; climate_determine_future_weather(); - RCT2_GLOBAL(0x009A9804, uint32) |= 8; // climate dirty flag? + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint32) |= BTM_TB_DIRTY_FLAG_CLIMATE; } else if (next_rain <= 2) { // Safe-guard RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, sint8) = step_weather_level(cur_rain, next_rain); } @@ -160,14 +189,12 @@ void climate_update() } else { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, sint8) = step_weather_level(temperature, target_temperature); - RCT2_GLOBAL(0x009A9804, uint32) |= 8; // climate dirty flag? + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint32) |= BTM_TB_DIRTY_FLAG_CLIMATE; } } } void climate_force_weather(uint8 weather){ - gClimateNextWeather = 0; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER, sint8) = weather; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_GLOOM, sint8) = climate_weather_data[weather].gloom_level; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, sint8) = climate_weather_data[weather].rain_level; @@ -175,6 +202,9 @@ void climate_force_weather(uint8 weather){ RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE_UPDATE_TIMER, sint16) = 1920; climate_update(); + + // Incase of change in gloom level force a complete redraw + gfx_invalidate_screen(); } /** @@ -216,7 +246,7 @@ void climate_update_sound() return; if (!(RCT2_GLOBAL(0x009AF59D, uint8) & 1)) return; - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1) + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) return; climate_update_rain_sound(); @@ -463,4 +493,4 @@ static const rct_weather_transition* climate_transitions[] = { climate_cold_transitions }; -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/world/climate.h b/src/world/climate.h index 4da09de4ab..0ab10b5be3 100644 --- a/src/world/climate.h +++ b/src/world/climate.h @@ -47,7 +47,10 @@ typedef struct { uint32 sprite_id; } rct_weather; -extern int gClimateNextWeather; +// This still needs to be read / written when loading and saving +// extern int gClimateNextWeather; +#define gClimateNextWeather RCT2_GLOBAL(0x013CA74B, uint8) + extern const rct_weather climate_weather_data[6]; // cheats diff --git a/src/toolbar.h b/src/world/entrance.h similarity index 53% rename from src/toolbar.h rename to src/world/entrance.h index 4c216c99a4..6705c623f0 100644 --- a/src/toolbar.h +++ b/src/world/entrance.h @@ -18,30 +18,16 @@ * along with this program. If not, see . *****************************************************************************/ -#ifndef _TOOLBAR_H_ -#define _TOOLBAR_H_ +#ifndef _ENTRANCE_H_ +#define _ENTRANCE_H_ -#include "interface/window.h" -#include "interface/widget.h" +#include "../common.h" -typedef enum { - DDIDX_UNDERGROUND_INSIDE = 0, - DDIDX_HIDE_BASE = 1, - DDIDX_HIDE_VERTICAL = 2, - DDIDX_SEETHROUGH_RIDES = 4, - DDIDX_SEETHROUGH_SCENARY = 5, - DDIDX_INVISIBLE_SUPPORTS = 6, - DDIDX_INVISIBLE_PEEPS = 7, - DDIDX_LAND_HEIGHTS = 9, - DDIDX_TRACK_HEIGHTS = 10, - DDIDX_PATH_HEIGHTS = 11, -} TOP_TOOLBAR_VIEW_MENU_DDIDX; +typedef struct { + rct_string_id string_idx; // 0x00 + uint32 image_id; // 0x02 + uint8 var_06; + uint8 var_07; +} rct_entrance_type; -void top_toolbar_init_view_menu(rct_window* window, rct_widget* widget); -void top_toolbar_view_menu_dropdown(short dropdownIndex); - -void toggle_footpath_window(); -void toggle_land_window(rct_window* topToolbar, int widgetIndex); -void toggle_clear_scenery_window(rct_window* topToolbar, int widgetIndex); -void toggle_water_window(rct_window* topToolbar, int widgetIndex); -#endif +#endif \ No newline at end of file diff --git a/src/world/footpath.c b/src/world/footpath.c index 5622226a72..7caa8dbadf 100644 --- a/src/world/footpath.c +++ b/src/world/footpath.c @@ -20,8 +20,395 @@ #include "../addresses.h" #include "../game.h" +#include "../localisation/localisation.h" +#include "../util/util.h" #include "footpath.h" #include "map.h" +#include "scenery.h" +#include "../cheats.h" +#include "../config.h" + +void footpath_interrupt_peeps(int x, int y, int z); + +enum { + FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED = 1 << 3 +}; + +const rct_xy16 word_981D6C[] = { + { -1, 0 }, + { 0, 1 }, + { 1, 0 }, + { 0, -1 } +}; + +/** + * + * rct2: 0x006A65AD + */ +static void automatically_set_peep_spawn(int x, int y, int z) +{ + rct2_peep_spawn *peepSpawn = (rct2_peep_spawn*)RCT2_ADDRESS_PEEP_SPAWNS; + int direction = 0; + if (x != 32) { + direction++; + if (y != RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) - 32) { + direction++; + if (x != RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) - 32) { + direction++; + if (y != 32) + return; + } + } + } + + peepSpawn->x = x + (word_981D6C[direction].x * 15) + 16; + peepSpawn->y = y + (word_981D6C[direction].y * 15) + 16; + peepSpawn->direction = direction; + peepSpawn->z = z; +} + +rct_map_element *map_get_footpath_element(int x, int y, int z) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH && mapElement->base_height == z) + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + +rct_map_element *map_get_footpath_element_slope(int x, int y, int z, int slope) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x, y); + do { + if ( + map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH && + mapElement->base_height == z && + (mapElement->properties.path.type & 7) == slope + ) { + return mapElement; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + +static void loc_6A6620(int flags, int x, int y, rct_map_element *mapElement) +{ + int direction, z; + + if ((mapElement->properties.path.type & 4) && !(flags & (1 << 6))) { + direction = mapElement->properties.path.type & 3; + z = mapElement->base_height; + map_remove_intersecting_walls(x, y, z, z + 6, direction ^ 2); + map_remove_intersecting_walls(x, y, z, z + 6, direction); + mapElement = map_get_footpath_element(x / 32, y / 32, z); + } + + if (!(flags & (1 << 7))) + sub_6A6C66(x, y, mapElement, flags); + + sub_6A759F(); + map_invalidate_tile_full(x, y); +} + +static money32 footpath_element_insert(int type, int x, int y, int z, int slope, int flags) +{ + rct_map_element *mapElement; + int bl, zHigh; + + if (!sub_68B044()) + return MONEY32_UNDEFINED; + + if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & (FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED | (1 << 6)))) + footpath_remove_litter(x, y, RCT2_GLOBAL(0x009DEA62, uint16)); + + // loc_6A649D: + RCT2_GLOBAL(0x00F3EFD9, money32) += MONEY(12, 00); + + bl = 15; + zHigh = z + 4; + if (slope & 4) { + bl = RCT2_ADDRESS(0x0098D7EC, uint8)[slope & 3]; + zHigh += 2; + } + + RCT2_GLOBAL(0x00F3EF84, uint16) = x; + RCT2_GLOBAL(0x00F3EF86, uint16) = y; + + // Ugh, hack until 0x006A6733 is written + // 0x006A6733 expects the flags to be at (*0xF3EF7C) + 8 + RCT2_GLOBAL(0x00F3EF7C, uint32) = (uint32)(&flags - 2); + + if (!map_can_construct_with_clear_at(x, y, z, zHigh, (void*)0x006A6733, bl)) + return MONEY32_UNDEFINED; + + RCT2_GLOBAL(0x00F3EFA4, uint8) = RCT2_GLOBAL(0x00F1AD60, uint8); + if (RCT2_GLOBAL(0x00F1AD60, uint8) & 4) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANT_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + + mapElement = map_get_surface_element_at((x / 32), (y / 32)); + + int supportHeight = z - mapElement->base_height; + RCT2_GLOBAL(0x00F3EFD9, money32) += supportHeight < 0 ? MONEY(20, 00) : (supportHeight / 2) * MONEY(5, 00); + + if (flags & GAME_COMMAND_FLAG_APPLY) { + mapElement = map_element_insert(x / 32, y / 32, z, 0x0F); + mapElement->type = MAP_ELEMENT_TYPE_PATH; + mapElement->clearance_height = z + 4 + (slope & 4 ? 2 : 0); + mapElement->properties.path.type = (type << 4) | (slope & 7); + mapElement->type |= type >> 7; + mapElement->properties.path.additions = RCT2_GLOBAL(0x00F3EF88, uint8); + mapElement->properties.path.addition_status = 255; + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + if (flags & (1 << 6)) + mapElement->flags |= 1 << 4; + + RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; + + if (!(flags & (1 << 7))) + sub_6A6AA7(x, y, mapElement); + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & (1 << 6))) + automatically_set_peep_spawn(x, y, mapElement->base_height / 2); + + loc_6A6620(flags, x, y, mapElement); + } + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); +} + +static money32 footpath_element_update(int x, int y, rct_map_element *mapElement, int type, int flags) +{ + if ((mapElement->properties.path.type >> 4) != (type & 0x0F) || (mapElement->type & 1) != (type >> 7)) { + RCT2_GLOBAL(0x00F3EFD9, money32) += MONEY(6, 00); + } else if (RCT2_GLOBAL(0x00F3EF88, uint16) != 0) { + if ( + !(flags & (1 << 6)) && + (mapElement->properties.path.additions & 0x0F) == RCT2_GLOBAL(0x00F3EF88, uint16) && + !(mapElement->flags & MAP_ELEMENT_FLAG_BROKEN) + ) { + if (flags & (1 << 4)) + return MONEY32_UNDEFINED; + + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); + } + + if (RCT2_GLOBAL(0x00F3EF88, uint16) != 0) { + rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[RCT2_GLOBAL(0x00F3EF88, uint16) - 1]; + uint16 unk6 = scenery_entry->path_bit.var_06; + + if ((unk6 & 0x80) && (mapElement->properties.path.type & 4)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANT_BUILD_THIS_ON_SLOPED_FOOTPATH; + return MONEY32_UNDEFINED; + } + + if ((unk6 & 0x40) && (mapElement->type & 1)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANNOT_PLACE_THESE_ON_QUEUE_LINE_AREA; + return MONEY32_UNDEFINED; + } + + if ((unk6 & 0x30) && (mapElement->properties.path.edges & 0x0F) == 0x0F) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NONE; + return MONEY32_UNDEFINED; + } + + if ((unk6 & 0x100) && !(mapElement->type & 1)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA; + return MONEY32_UNDEFINED; + } + + RCT2_GLOBAL(0x00F3EFD9, money32) += scenery_entry->path_bit.price; + } + + if (flags & (1 << 4)) + return MONEY32_UNDEFINED; + + if (flags & (1 << 6)) { + if (mapElement->properties.path.additions & 0x0F) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NONE; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) + mapElement->properties.path.additions |= 0x80; + } + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); + + if ( + ( + RCT2_GLOBAL(0x00F3EF88, uint16) != 0 && + !(flags & (1 << 6)) + ) || + ( + RCT2_GLOBAL(0x00F3EF88, uint16) == 0 || + (mapElement->properties.path.additions & 0x80) + ) + ) { + mapElement->properties.path.additions &= ~0x80; + } + + mapElement->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | RCT2_GLOBAL(0x00F3EF88, uint8); + mapElement->flags &= ~0x20; + if (RCT2_GLOBAL(0x00F3EF88, uint16) != 0) { + rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[RCT2_GLOBAL(0x00F3EF88, uint16) - 1]; + uint16 unk6 = scenery_entry->path_bit.var_06; + if (unk6 & 1) + mapElement->properties.path.addition_status = 255; + } + map_invalidate_tile_full(x, y); + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); + } + + if (flags & (1 << 4)) + return MONEY32_UNDEFINED; + + if (flags & GAME_COMMAND_FLAG_APPLY) { + RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; + + if (!(flags & (1 << 7))) + sub_6A6AA7(x, y, mapElement); + + mapElement->properties.path.type = (mapElement->properties.path.type & 0x0F) | (type << 4); + mapElement->type = (mapElement->type & 0xFE) | (type >> 7); + mapElement->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | RCT2_GLOBAL(0x00F3EF88, uint8); + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + + loc_6A6620(flags, x, y, mapElement); + } + + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); +} + +static money32 footpath_place_real(int type, int x, int y, int z, int slope, int flags, uint8 path_bit_type) +{ + rct_map_element *mapElement; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z * 8; + + if (!(flags & FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) + footpath_interrupt_peeps(x, y, z * 8); + + RCT2_GLOBAL(0x00F3EFD9, money32) = 0; + RCT2_GLOBAL(0x00F3EFA4, uint8) = 0; + RCT2_GLOBAL(0x00F3EF88, uint16) = path_bit_type; // di + + if (x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) || y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_OFF_EDGE_OF_MAP; + return MONEY32_UNDEFINED; + } + + if (!((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gSandboxMode) && !map_is_location_owned(x, y, z * 8)) + return MONEY32_UNDEFINED; + + if (slope & 8) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_LAND_SLOPE_UNSUITABLE; + return MONEY32_UNDEFINED; + } + + if (z < 2) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_LOW; + return MONEY32_UNDEFINED; + } + + if (z > 248) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } + + mapElement = map_get_footpath_element_slope((x / 32), (y / 32), z, slope); + return mapElement == NULL ? + footpath_element_insert(type, x, y, z, slope, flags) : + footpath_element_update(x, y, mapElement, type, flags); +} + +/* rct2: 0x006BA23E */ +void remove_banners_at_element(int x, int y, rct_map_element* mapElement){ + while (!map_element_is_last_for_tile(mapElement++)){ + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH)return; + else if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_BANNER)continue; + + game_do_command(x, 1, y, mapElement->base_height | mapElement->properties.banner.position << 8, GAME_COMMAND_REMOVE_BANNER, 0, 0); + mapElement--; + } +} + +money32 footpath_remove_real(int x, int y, int z, int flags) +{ + rct_map_element *mapElement; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z * 8; + + if (!(flags & FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + footpath_interrupt_peeps(x, y, z * 8); + footpath_remove_litter(x, y, z * 8); + } + + if (!((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gSandboxMode) && !map_is_location_owned(x, y, z * 8)) + return MONEY32_UNDEFINED; + + mapElement = map_get_footpath_element(x / 32, y / 32, z); + if (mapElement != NULL && (flags & GAME_COMMAND_FLAG_APPLY)) { + RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; + remove_banners_at_element(x, y, mapElement); + sub_6A6AA7(x, y, mapElement); + map_invalidate_tile_full(x, y); + map_element_remove(mapElement); + sub_6A759F(); + } + + return (flags & (1 << 5)) || (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? 0 : -MONEY(10,00); +} + +/** + * + * rct2: 0x006A61DE + */ +void game_command_place_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + if (*ebx & (1 << 5)) + RCT2_CALLFUNC_X(0x006A61DE, eax, ebx, ecx, edx, esi, edi, ebp); + else + *ebx = footpath_place_real((*edx >> 8) & 0xFF, *eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*ebx >> 8) & 0xFF, *ebx & 0xFF, *edi & 0xFF); +} + +/** + * + * rct2: 0x006A67C0 + */ +void game_command_remove_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = footpath_remove_real((*eax & 0xFFFF), (*ecx & 0xFFFF), (*edx & 0xFF), (*ebx & 0xFF)); +} + +money32 footpath_place(int type, int x, int y, int z, int slope, int flags) +{ + return game_do_command(x, (slope << 8) | flags, y, (type << 8) | z, GAME_COMMAND_PLACE_PATH, 0, 0); +} void footpath_remove(int x, int y, int z, int flags) { @@ -30,9 +417,32 @@ void footpath_remove(int x, int y, int z, int flags) /** * - * rct2: 0x006A7FFF + * rct2: 0x006A76FF */ -void sub_6A7FFF() +money32 footpath_provisional_set(int type, int x, int y, int z, int slope) +{ + money32 cost; + + footpath_provisional_remove(); + + cost = footpath_place(type, x, y, z, slope, (1 << 6) | (1 << 5) | (1 << 4) | FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_APPLY); + if (cost != MONEY32_UNDEFINED) { + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint8) = z & 0xFF; + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) |= (1 << 1); + + viewport_set_visibility(RCT2_GLOBAL(0x00F3EFA4, uint8) & 2 ? 1 : 3); + } + + return cost; +} + +/** + * + * rct2: 0x006A77FF + */ +void footpath_provisional_remove() { if (RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & (1 << 1)) { RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) &= ~(1 << 1); @@ -41,7 +451,7 @@ void sub_6A7FFF() RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint16), - 41 + (1 << 0) | FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED | (1 << 5) ); } } @@ -50,17 +460,273 @@ void sub_6A7FFF() * * rct2: 0x006A7831 */ -void sub_6A7831() +void footpath_provisional_update() { - if (RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & (1 << 0)) { - RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) &= ~(1 << 0); + if (RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & PROVISIONAL_PATH_FLAG_SHOW_ARROW) { + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) &= ~PROVISIONAL_PATH_FLAG_SHOW_ARROW; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint8) &= ~(1 << 2); map_invalidate_tile_full( RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) ); - } else { - sub_6A7FFF(); } -} \ No newline at end of file + footpath_provisional_remove(); +} + +/** + * Determines the location of the footpath at which we point with the cursor. If no footpath is underneath the cursor, + * then return the location of the ground tile. Besides the location it also computes the direction of the yellow arrow + * when we are going to build a footpath bridge/tunnel. + * rct2: 0x00689726 + * In: + * screenX: eax + * screenY: ebx + * Out: + * x: ax + * y: bx + * direction: ecx + * mapElement: edx + */ +void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement) +{ + int z, interactionType; + rct_map_element *myMapElement; + rct_viewport *viewport; + rct_xy16 map_pos = { 0 }; + + get_map_coordinates_from_pos(screenX, screenY, VIEWPORT_INTERACTION_MASK_FOOTPATH, &map_pos.x, &map_pos.y, &interactionType, &myMapElement, &viewport); + if (interactionType != VIEWPORT_INTERACTION_ITEM_FOOTPATH || !(viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL))) { + get_map_coordinates_from_pos(screenX, screenY, VIEWPORT_INTERACTION_MASK_FOOTPATH & VIEWPORT_INTERACTION_MASK_TERRAIN, &map_pos.x, &map_pos.y, &interactionType, &myMapElement, &viewport); + if (interactionType == VIEWPORT_INTERACTION_ITEM_NONE) { + if (x != NULL) *x = (sint16)0x8000; + return; + } + } + + RCT2_GLOBAL(0x00F1AD3E, uint8) = interactionType; + RCT2_GLOBAL(0x00F1AD30, rct_map_element*) = myMapElement; + + if (interactionType == VIEWPORT_INTERACTION_ITEM_FOOTPATH) { + z = myMapElement->base_height * 8; + if (myMapElement->properties.path.type & (1 << 2)) + z += 8; + } + + RCT2_GLOBAL(0x00F1AD3C, uint16) = z; + RCT2_GLOBAL(0x00F1AD34, sint16) = map_pos.x; + RCT2_GLOBAL(0x00F1AD36, sint16) = map_pos.y; + RCT2_GLOBAL(0x00F1AD38, sint16) = map_pos.x + 31; + RCT2_GLOBAL(0x00F1AD3A, sint16) = map_pos.y + 31; + + map_pos.x += 16; + map_pos.y += 16; + + rct_xy16 start_vp_pos = screen_coord_to_viewport_coord(viewport, screenX, screenY); + + for (int i = 0; i < 5; i++) { + if (RCT2_GLOBAL(0x00F1AD3E, uint8) != 6) { + z = map_element_height(map_pos.x, map_pos.y); + } else { + z = RCT2_GLOBAL(0x00F1AD3C, uint16); + } + map_pos = viewport_coord_to_map_coord(start_vp_pos.x, start_vp_pos.y, z); + map_pos.x = clamp(RCT2_GLOBAL(0x00F1AD34, sint16), map_pos.x, RCT2_GLOBAL(0x00F1AD38, sint16)); + map_pos.y = clamp(RCT2_GLOBAL(0x00F1AD36, sint16), map_pos.y, RCT2_GLOBAL(0x00F1AD3A, sint16)); + } + + // Determine to which edge the cursor is closest + uint32 myDirection; + int mod_x = map_pos.x & 0x1F, mod_y = map_pos.y & 0x1F; + if (mod_x < mod_y) { + if (mod_x + mod_y < 32) { + myDirection = 0; + } else { + myDirection = 1; + } + } else { + if (mod_x + mod_y < 32) { + myDirection = 3; + } else { + myDirection = 2; + } + } + + if (x != NULL) *x = map_pos.x & ~0x1F; + if (y != NULL) *y = map_pos.y & ~0x1F; + if (direction != NULL) *direction = myDirection; + if (mapElement != NULL) *mapElement = myMapElement; + // We should get the rct_map_element from 0x00F1AD30 here, but we set it earlier to our myMapElement anyway. +} + +/** + * + * rct2: 0x0068A0C9 + * screenX: eax + * screenY: ebx + * x: ax + * y: bx + * direction: cl + * mapElement: edx + */ +void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement) +{ + // First check if we point at an entrance or exit. In that case, we would want the path coming from the entrance/exit. + int interactionType; + rct_viewport *viewport; + + rct_xy16 map_pos = { 0 }; + get_map_coordinates_from_pos(screenX, screenY, VIEWPORT_INTERACTION_MASK_RIDE, &map_pos.x, &map_pos.y, &interactionType, mapElement, &viewport); + *x = map_pos.x; + *y = map_pos.y; + + if (interactionType == VIEWPORT_INTERACTION_ITEM_RIDE + && viewport->flags & (VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL) + && map_element_get_type(*mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { + int ebp = (*mapElement)->properties.entrance.type << 4; + int bl = (*mapElement)->properties.entrance.index & 0xF; + if (RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16) & 0xF) { + int bx = bitscanforward(RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16)); + bx += (*mapElement)->type; + bx &= 3; + if (direction != NULL) *direction = bx; + return; + } + } + + get_map_coordinates_from_pos(screenX, screenY, VIEWPORT_INTERACTION_MASK_RIDE & VIEWPORT_INTERACTION_MASK_FOOTPATH & VIEWPORT_INTERACTION_MASK_TERRAIN, &map_pos.x, &map_pos.y, &interactionType, mapElement, &viewport); + *x = map_pos.x; + *y = map_pos.y; + if (interactionType == VIEWPORT_INTERACTION_ITEM_RIDE && map_element_get_type(*mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { + int ebp = (*mapElement)->properties.entrance.type << 4; + int bl = (*mapElement)->properties.entrance.index & 0xF; // Seems to be always 0? + // The table at 0x0097B974 is only 48 bytes big + if (RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16) & 0xF) { + int bx = bitscanforward(RCT2_GLOBAL(0x0097B974 + ebp + bl, uint16)); + bx += (*mapElement)->type; // First two bits seem to contain the direction of entrance/exit + bx &= 3; + if (direction != NULL) *direction = bx; + return; + } + } + + // We point at something else + footpath_get_coordinates_from_pos(screenX, screenY, x, y, direction, mapElement); +} + +/** + * + * rct2: 0x00673883 + */ +void footpath_remove_litter(int x, int y, int z) +{ + int index; + uint16 spriteIndex, nextSpriteIndex; + rct_litter *sprite; + + index = (x & 0x1FE0) << 3 | (y >> 5); + spriteIndex = RCT2_ADDRESS(0x00F1EF60, uint16)[index]; + while (spriteIndex != SPRITE_INDEX_NULL) { + sprite = &g_sprite_list[spriteIndex].litter; + nextSpriteIndex = sprite->next_in_quadrant; + if (sprite->linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_LITTER) { + int distanceZ = abs(sprite->z - z); + if (distanceZ <= 32) { + sub_6EC60B((rct_sprite*)sprite); + sprite_remove((rct_sprite*)sprite); + } + } + spriteIndex = nextSpriteIndex; + } +} + +/** + * + * rct2: 0x0069A48B + */ +void footpath_interrupt_peeps(int x, int y, int z) +{ + int index; + uint16 spriteIndex, nextSpriteIndex; + rct_peep *peep; + + index = (x & 0x1FE0) << 3 | (y >> 5); + spriteIndex = RCT2_ADDRESS(0x00F1EF60, uint16)[index]; + while (spriteIndex != SPRITE_INDEX_NULL) { + peep = &g_sprite_list[spriteIndex].peep; + nextSpriteIndex = peep->next_in_quadrant; + if (peep->linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_PEEP) { + if (peep->state == PEEP_STATE_SITTING || peep->state == PEEP_STATE_WATCHING) { + if (peep->z == 0) { + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_WALKING; + peep_window_state_update(peep); + peep->destination_x = (peep->x & 0xFFE0) + 16; + peep->destination_y = (peep->y & 0xFFE0) + 16; + peep->destination_tolerence = 5; + sub_693B58(peep); + } + } + } + spriteIndex = nextSpriteIndex; + } +} + +/** + * + * rct2: 0x006A6C66 + */ +void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags) +{ + RCT2_CALLPROC_X(0x006A6C66, x, flags, y, 0, (int)mapElement, 0, 0); +} + +/** + * + * rct2: 0x006A742F + */ +void sub_6A742F(int rideIndex, int entranceIndex, int x, int y, rct_map_element *mapElement, int direction) +{ + RCT2_CALLPROC_X(0x006A742F, x, direction, y, (entranceIndex << 8) | rideIndex, (int)mapElement, 0, 0); +} + +/** + * + * rct2: 0x006A759F + */ +void sub_6A759F() +{ + uint8 *esi; + int i, x, y, z, direction, rideIndex; + rct_ride *ride; + rct_map_element *mapElement; + + for (esi = (uint8*)0x00F3EFF8; esi < RCT2_GLOBAL(0x00F3EFF4, uint8*); esi++) { + rideIndex = *esi; + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_NULL) + continue; + + for (i = 0; i < 4; i++) { + if (ride->entrances[i] == 0xFFFF) + continue; + + x = ride->entrances[i] & 0xFF; + y = ride->entrances[i] >> 8; + z = ride->station_heights[i]; + + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (mapElement->base_height != z) + continue; + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_RIDE_ENTRANCE) + continue; + + direction = (mapElement->type & 3) ^ 2; + sub_6A742F(rideIndex, i, x << 5, y << 5, mapElement, direction); + } while (!map_element_is_last_for_tile(mapElement++)); + } + } +} diff --git a/src/world/footpath.h b/src/world/footpath.h index 7fb2986296..047773a653 100644 --- a/src/world/footpath.h +++ b/src/world/footpath.h @@ -22,17 +22,34 @@ #define _WORLD_FOOTPATH_H_ #include "../common.h" +#include "../interface/viewport.h" +#include "../object.h" + +enum { + PROVISIONAL_PATH_FLAG_SHOW_ARROW = (1 << 0) +}; typedef struct { - uint16 pad_00; - uint32 image; // 0x02 - uint32 pad_06; - uint8 pad_0A; - uint8 flags; // 0x0B + rct_string_id string_idx; // 0x00 + uint32 image; // 0x02 + uint32 bridge_image; // 0x06 + uint8 var_0A; + uint8 flags; // 0x0B } rct_path_type; +#define g_pathTypeEntries ((rct_path_type**)object_entry_groups[OBJECT_TYPE_PATHS].chunks) + +void game_command_place_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_remove_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +money32 footpath_place(int type, int x, int y, int z, int slope, int flags); void footpath_remove(int x, int y, int z, int flags); -void sub_6A7FFF(); -void sub_6A7831(); +money32 footpath_provisional_set(int type, int x, int y, int z, int slope); +void footpath_provisional_remove(); +void footpath_provisional_update(); +void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); +void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); +void footpath_remove_litter(int x, int y, int z); +void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags); +void sub_6A759F(); #endif diff --git a/src/world/fountain.c b/src/world/fountain.c index 70740961f2..c034d2fc46 100644 --- a/src/world/fountain.c +++ b/src/world/fountain.c @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2014 Ted John, Peter Hill + * Copyright (c) 2014 Ted John * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * This file is part of OpenRCT2. @@ -19,19 +19,427 @@ *****************************************************************************/ #include "../addresses.h" -#include "../game.h" -#include "../common.h" +#include "../scenario.h" +#include "fountain.h" +#include "map.h" +#include "scenery.h" +#include "sprite.h" + +enum { + PATTERN_CYCLIC_SQUARES, + PATTERN_CONTINUOUS_CHASERS, + PATTERN_BOUNCING_PAIRS, + PATTERN_SPROUTING_BLOOMS, + PATTERN_RACING_PAIRS, + PATTERN_SPLITTING_CHASERS, + PATTERN_DOPEY_JUMPERS, + PATTERN_FAST_RANDOM_CHASERS +}; + +enum { + FOUNTAIN_FLAG_FAST = 1 << 0, + FOUNTAIN_FLAG_GOTO_EDGE = 1 << 1, + FOUNTAIN_FLAG_SPLIT = 1 << 2, + FOUNTAIN_FLAG_TERMINATE = 1 << 3, + FOUNTAIN_FLAG_BOUNCE = 1 << 4, + FOUNTAIN_FLAG_7 = 1 << 7 +}; + +const rct_xy16 dword_97F000[] = { + { -32, 0 }, + { -32, -32 }, + { 0, 0 }, + { -32, 0 }, + { 0, 0 }, + { 0, -32 }, + { 0, -32 }, + { -32, -32 }, +}; + +const rct_xy16 dword_97F020[] = { + { 32, 0 }, + { 0, 0 }, + { 0, 32 }, + { 32, 32 }, + { 32, 32 }, + { 32, 0 }, + { 0, 0 }, + { 0, 32 } +}; + +// rct2: 0x0097F040 +const uint8 _fountainDirections[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; + +// rct2: 0x0097F048 +const uint8 _fountainDirectionFlags[] = { 0, 0, FOUNTAIN_FLAG_7, FOUNTAIN_FLAG_7, FOUNTAIN_FLAG_7, FOUNTAIN_FLAG_7, 0, 0 }; + +// rct2: 0x0097F050 +const uint8 _fountainPatternFlags[] = { + FOUNTAIN_FLAG_TERMINATE, // PATTERN_CYCLIC_SQUARES + FOUNTAIN_FLAG_FAST | FOUNTAIN_FLAG_GOTO_EDGE, // PATTERN_CONTINUOUS_CHASERS + FOUNTAIN_FLAG_BOUNCE, // PATTERN_BOUNCING_PAIRS + FOUNTAIN_FLAG_FAST | FOUNTAIN_FLAG_SPLIT, // PATTERN_SPROUTING_BLOOMS + FOUNTAIN_FLAG_GOTO_EDGE, // PATTERN_RACING_PAIRS + FOUNTAIN_FLAG_FAST | FOUNTAIN_FLAG_GOTO_EDGE | FOUNTAIN_FLAG_SPLIT, // PATTERN_SPLITTING_CHASERS + 0, // PATTERN_DOPEY_JUMPERS + FOUNTAIN_FLAG_FAST // PATTERN_FAST_RANDOM_CHASERS +}; + +static void jumping_fountain_continue(rct_jumping_fountain *jumpingFountain); +static bool is_jumping_fountain(int type, int x, int y, int z); + +static void jumping_fountain_goto_edge(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections); +static void jumping_fountain_bounce(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections); +static void jumping_fountain_split(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections); +static void jumping_fountain_random(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections); +static void jumping_fountain_create_next(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int direction); /** * - * rct2: 0x006646E1 + * rct2: 0x00673DBA (water) + * rct2: 0x00673F51 (snow) */ -void fountain_update_all() +void jumping_fountain_begin(int type, int x, int y, rct_map_element *mapElement) { - int ignoreScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER; - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & ignoreScreenFlags) + int i, randomIndex; + int z = mapElement->base_height * 8; + + // Change pattern approximately every 51 seconds + int pattern = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) >> 11) & 7; + switch (pattern) { + case PATTERN_CYCLIC_SQUARES: + // 0, 1, 2, 3 + for (i = 0; i < 4; i++) { + jumping_fountain_create( + type, + x + dword_97F020[i].x, + y + dword_97F020[i].y, + z, + _fountainDirections[i], + _fountainDirectionFlags[i] | _fountainPatternFlags[pattern], + 0 + ); + } + break; + case PATTERN_BOUNCING_PAIRS: + // random [0, 2 or 1, 3] + randomIndex = scenario_rand() & 1; + for (i = randomIndex; i < 4; i += 2) { + jumping_fountain_create( + type, + x + dword_97F020[i].x, + y + dword_97F020[i].y, + z, + _fountainDirections[i], + _fountainDirectionFlags[i] | _fountainPatternFlags[pattern], + 0 + ); + } + break; + case PATTERN_RACING_PAIRS: + // random [0 - 3 and 4 - 7] + z = mapElement->base_height * 8; + randomIndex = scenario_rand() & 3; + jumping_fountain_create( + type, + x + dword_97F020[randomIndex].x, + y + dword_97F020[randomIndex].y, + z, + _fountainDirections[randomIndex], + _fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern], + 0 + ); + randomIndex += 4; + jumping_fountain_create( + type, + x + dword_97F020[randomIndex].x, + y + dword_97F020[randomIndex].y, + z, + _fountainDirections[randomIndex], + _fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern], + 0 + ); + break; + default: + // random [0 - 7] + randomIndex = scenario_rand() & 7; + jumping_fountain_create( + type, + x + dword_97F020[randomIndex].x, + y + dword_97F020[randomIndex].y, + z, + _fountainDirections[randomIndex], + _fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern], + 0 + ); + break; + } +} + +/** + * + * rct2: 0x0067396A (water) + * rct2: 0x006739A4 (snow) + */ +void jumping_fountain_create(int type, int x, int y, int z, int direction, int flags, int iteration) +{ + rct_jumping_fountain *jumpingFountain; + + jumpingFountain = (rct_jumping_fountain*)create_sprite(SPRITE_IDENTIFIER_MISC); + if (jumpingFountain == NULL) return; - // Probably not just fountains... may include scenery aging and grass growth. - RCT2_CALLPROC_EBPSAFE(0x006646EE); + jumpingFountain->iteration = iteration; + jumpingFountain->var_2E = direction; + jumpingFountain->flags = flags; + jumpingFountain->sprite_direction = direction << 3; + jumpingFountain->var_14 = 33; + jumpingFountain->var_09 = 36; + jumpingFountain->var_15 = 12; + jumpingFountain->sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite_move(x, y, z, (rct_sprite*)jumpingFountain); + jumpingFountain->misc_identifier = type == JUMPING_FOUNTAIN_TYPE_SNOW ? + SPRITE_MISC_JUMPING_FOUNTAIN_SNOW : + SPRITE_MISC_JUMPING_FOUNTAIN_WATER; + jumpingFountain->var_26 = 0; +} + +/** + * + * rct: 0x006733CB (water) + * rct: 0x00673407 (snow) + */ +void jumping_fountain_update(rct_jumping_fountain *jumpingFountain) +{ + int original_var_26a = jumpingFountain->var_26a; + jumpingFountain->var_26a += 160; + if (original_var_26a <= 255 - 160) + return; + + sub_6EC60B((rct_sprite*)jumpingFountain); + jumpingFountain->var_26b++; + + switch (jumpingFountain->misc_identifier) { + case SPRITE_MISC_JUMPING_FOUNTAIN_WATER: + if (jumpingFountain->var_26b == 11 && (jumpingFountain->flags & FOUNTAIN_FLAG_FAST)) + jumping_fountain_continue(jumpingFountain); + + if (jumpingFountain->var_26b == 16 && !(jumpingFountain->flags & FOUNTAIN_FLAG_FAST)) + jumping_fountain_continue(jumpingFountain); + break; + case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW: + if (jumpingFountain->var_26b == 16) + jumping_fountain_continue(jumpingFountain); + break; + } + + if (jumpingFountain->var_26b == 16) + sprite_remove((rct_sprite*)jumpingFountain); +} + +/** + * + * rct2: 0x006739DE (water) + * rct2: 0x00673BCC (snow) + */ +static void jumping_fountain_continue(rct_jumping_fountain *jumpingFountain) +{ + int direction = (jumpingFountain->sprite_direction >> 3) & 7; + int x = jumpingFountain->x + TileDirectionDelta[direction].x; + int y = jumpingFountain->y + TileDirectionDelta[direction].y; + int z = jumpingFountain->z; + + int type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ? + JUMPING_FOUNTAIN_TYPE_SNOW : + JUMPING_FOUNTAIN_TYPE_WATER; + + int availableDirections = 0; + for (int i = 0; i < 8; i++) { + if (is_jumping_fountain(type, x + dword_97F000[i].x, y + dword_97F000[i].y, z)) + availableDirections |= 1 << i; + } + + if (availableDirections == 0) + return; + + if (jumpingFountain->flags & FOUNTAIN_FLAG_TERMINATE) + return; + + if (jumpingFountain->flags & FOUNTAIN_FLAG_GOTO_EDGE) { + jumping_fountain_goto_edge(jumpingFountain, x, y, z, availableDirections); + return; + } + + if (jumpingFountain->flags & FOUNTAIN_FLAG_BOUNCE) { + jumping_fountain_bounce(jumpingFountain, x, y, z, availableDirections); + return; + } + + if (jumpingFountain->flags & FOUNTAIN_FLAG_SPLIT) { + jumping_fountain_split(jumpingFountain, x, y, z, availableDirections); + return; + } + + jumping_fountain_random(jumpingFountain, x, y, z, availableDirections); +} + +static bool is_jumping_fountain(int type, int x, int y, int z) +{ + z = z >> 3; + + int pathBitFlagMask = type == JUMPING_FOUNTAIN_TYPE_SNOW ? + PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW : + PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER; + + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + if (mapElement->base_height != z) + continue; + if (mapElement->properties.path.additions & 0x80) + continue; + + int additions = mapElement->properties.path.additions & 0x0F; + if (additions == 0) + continue; + + rct_scenery_entry *sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (!(sceneryEntry->path_bit.var_06 & pathBitFlagMask)) + continue; + + return true; + } while (!map_element_is_last_for_tile(mapElement++)); + + return false; +} + +/** + * + * rct: 0x00673B6E + */ +static void jumping_fountain_goto_edge(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections) +{ + int direction = (jumpingFountain->sprite_direction >> 3) << 1; + if (availableDirections & (1 << direction)) { + jumping_fountain_create_next(jumpingFountain, x, y, z, direction); + return; + } + + direction++; + if (availableDirections & (1 << direction)) { + jumping_fountain_create_next(jumpingFountain, x, y, z, direction); + return; + } + + uint32 randomIndex = scenario_rand(); + if ((randomIndex & 0xFFFF) < 0x3333) + return; + + if (jumpingFountain->flags & FOUNTAIN_FLAG_SPLIT) { + jumping_fountain_split(jumpingFountain, x, y, z, availableDirections); + return; + } + + direction = randomIndex & 7; + while (!(availableDirections & (1 << direction))) + direction = (direction + 1) & 7; + + jumping_fountain_create_next(jumpingFountain, x, y, z, direction); +} + +/** + * + * rct: 0x00673B45 + */ +static void jumping_fountain_bounce(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections) +{ + jumpingFountain->iteration++; + if (jumpingFountain->iteration >= 8) + return; + + int direction = ((jumpingFountain->sprite_direction >> 3) ^ 2) << 1; + if (availableDirections & (1 << direction)) { + jumping_fountain_create_next(jumpingFountain, x, y, z, direction); + return; + } + + direction++; + if (availableDirections & (1 << direction)) + jumping_fountain_create_next(jumpingFountain, x, y, z, direction); +} + +/** + * + * rct: 0x00673ACE + */ +static void jumping_fountain_split(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections) +{ + if (jumpingFountain->iteration >= 3) + return; + + int type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ? + JUMPING_FOUNTAIN_TYPE_SNOW : + JUMPING_FOUNTAIN_TYPE_WATER; + + int direction = ((jumpingFountain->sprite_direction >> 3) ^ 2) << 1; + availableDirections &= ~(1 << direction); + direction++; + availableDirections &= ~(1 << direction); + + for (direction = 0; direction < 8; direction++) { + if (availableDirections & (1 << direction)) { + jumping_fountain_create( + type, + x, y, z, + direction >> 1, + jumpingFountain->flags & ~FOUNTAIN_FLAG_7, + jumpingFountain->iteration + 1 + ); + } + direction++; + if (availableDirections & (1 << direction)) { + jumping_fountain_create( + type, + x, y, z, + direction >> 1, + jumpingFountain->flags | FOUNTAIN_FLAG_7, + jumpingFountain->iteration + 1 + ); + } + } +} + +/** + * + * rct: 0x00673AAC + */ +static void jumping_fountain_random(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections) +{ + uint32 randomIndex = scenario_rand(); + if ((randomIndex & 0xFFFF) < 0x2000) + return; + + int direction = randomIndex & 7; + while (!(availableDirections & (1 << direction))) + direction = (direction + 1) & 7; + + jumping_fountain_create_next(jumpingFountain, x, y, z, direction); +} + +/** + * + * rct: 0x00673B45 + */ +static void jumping_fountain_create_next(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int direction) +{ + int flags = jumpingFountain->flags & ~FOUNTAIN_FLAG_7; + if (direction & 1) + flags |= FOUNTAIN_FLAG_7; + + int type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ? + JUMPING_FOUNTAIN_TYPE_SNOW : + JUMPING_FOUNTAIN_TYPE_WATER; + + jumping_fountain_create(type, x, y, z, direction >> 1, flags, jumpingFountain->iteration); } \ No newline at end of file diff --git a/src/world/fountain.h b/src/world/fountain.h new file mode 100644 index 0000000000..d7b63fe148 --- /dev/null +++ b/src/world/fountain.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 _WORLD_FOUNTAIN_H_ +#define _WORLD_FOUNTAIN_H_ + +#include "../common.h" +#include "map.h" +#include "sprite.h" + +enum { + JUMPING_FOUNTAIN_TYPE_WATER, + JUMPING_FOUNTAIN_TYPE_SNOW +}; + +void jumping_fountain_begin(int type, int x, int y, rct_map_element *mapElement); +void jumping_fountain_create(int type, int x, int y, int z, int direction, int flags, int iteration); +void jumping_fountain_update(rct_jumping_fountain *jumpingFountain); + +#endif diff --git a/src/world/map.c b/src/world/map.c index 68cdda37fa..6de77a8521 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -19,18 +19,131 @@ *****************************************************************************/ #include "../addresses.h" +#include "../audio/audio.h" +#include "../game.h" +#include "../interface/window.h" #include "../localisation/date.h" #include "../localisation/localisation.h" +#include "../management/finance.h" +#include "../scenario.h" +#include "banner.h" #include "climate.h" +#include "footpath.h" #include "map.h" +#include "map_animation.h" #include "park.h" #include "scenery.h" +#include "../cheats.h" +#include "../config.h" + +const rct_xy16 TileDirectionDelta[] = { + { -32, 0 }, + { 0, +32 }, + { +32, 0 }, + { 0, -32 }, + { -32, +32 }, + { +32, +32 }, + { +32, -32 }, + { -32, -32 } +}; + +rct_xy16 *gMapSelectionTiles = (rct_xy16*)0x009DE596; + +bool LandPaintMode; +bool LandRightsMode; +bool gClearSmallScenery; +bool gClearLargeScenery; +bool gClearFootpath; int _sub_6A876D_save_x; int _sub_6A876D_save_y; static void tiles_init(); static void sub_6A87BB(int x, int y); +static void map_update_grass_length(int x, int y, rct_map_element *mapElement); +static void map_set_grass_length(int x, int y, rct_map_element *mapElement, int length); + +void rotate_map_coordinates(sint16* x, sint16* y, uint8 rotation){ + int temp; + switch (rotation){ + case MAP_ELEMENT_DIRECTION_WEST: + break; + case MAP_ELEMENT_DIRECTION_NORTH: + temp = *x; + *x = *y; + *y = -temp; + break; + case MAP_ELEMENT_DIRECTION_EAST: + *x = -*x; + *y = -*y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + temp = *y; + *y = *x; + *x = -temp; + break; + } +} + +void map_element_iterator_begin(map_element_iterator *it) +{ + it->x = 0; + it->y = 0; + it->element = map_get_first_element_at(0, 0); +} + +int map_element_iterator_next(map_element_iterator *it) +{ + if (it->element == NULL) { + it->element = map_get_first_element_at(it->x, it->y); + return 1; + } + + if (!map_element_is_last_for_tile(it->element)) { + it->element++; + return 1; + } + + if (it->x < 255) { + it->x++; + it->element = map_get_first_element_at(it->x, it->y); + return 1; + } + + if (it->y < 255) { + it->x = 0; + it->y++; + it->element = map_get_first_element_at(it->x, it->y); + return 1; + } + + return 0; +} + +void map_element_iterator_restart_for_tile(map_element_iterator *it) +{ + it->element = NULL; +} + +rct_map_element *map_get_first_element_at(int x, int y) +{ + if (x < 0 || y < 0 || x > 255 || y > 255) + { + log_error("Trying to access element outside of range"); + return NULL; + } + return TILE_MAP_ELEMENT_POINTER(x + y * 256); +} + +int map_element_is_last_for_tile(rct_map_element *element) +{ + return element->flags & MAP_ELEMENT_FLAG_LAST_TILE; +} + +int map_element_get_type(rct_map_element *element) +{ + return element->type & MAP_ELEMENT_TYPE_MASK; +} int map_element_get_terrain(rct_map_element *element) { @@ -58,7 +171,7 @@ void map_element_set_terrain(rct_map_element *element, int terrain) // Bits 0, 1, 2 for terrain are stored in element.terrain bit 5, 6, 7 element->properties.surface.terrain &= ~0xE0; - element->properties.surface.terrain = (terrain & 7) << 5; + element->properties.surface.terrain |= (terrain & 7) << 5; } void map_element_set_terrain_edge(rct_map_element *element, int terrain) @@ -76,13 +189,14 @@ void map_element_set_terrain_edge(rct_map_element *element, int terrain) rct_map_element *map_get_surface_element_at(int x, int y) { - // Get first element of the tile - rct_map_element *mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + rct_map_element *mapElement = map_get_first_element_at(x, y); + + if (mapElement == NULL) + return NULL; // Find the first surface element - while ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_SURFACE) { - // Check if last element on tile - if (mapElement->flags & MAP_ELEMENT_FLAG_LAST_TILE) + while (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SURFACE) { + if (map_element_is_last_for_tile(mapElement)) return NULL; mapElement++; @@ -91,11 +205,30 @@ rct_map_element *map_get_surface_element_at(int x, int y) return mapElement; } +rct_map_element* map_get_path_element_at(int x, int y, int z){ + rct_map_element *mapElement = map_get_first_element_at(x, y); + + if (mapElement == NULL) + return NULL; + + uint8 mapFound = 0; + // Find the path element at known z + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + if (mapElement->base_height != z) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} /** * * rct2: 0x0068AB4C */ -void map_init() +void map_init(int size) { int i; rct_map_element *map_element; @@ -113,18 +246,19 @@ void map_init() map_element->properties.surface.slope = 0; map_element->properties.surface.grass_length = 1; map_element->properties.surface.ownership = 0; + map_element->properties.surface.terrain = 0; map_element_set_terrain(map_element, TERRAIN_GRASS); map_element_set_terrain_edge(map_element, TERRAIN_EDGE_ROCK); } - RCT2_GLOBAL(0x013B0E70, sint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16) = 0; _sub_6A876D_save_x = 0; _sub_6A876D_save_y = 0; - RCT2_GLOBAL(0x01358830, sint16) = 4768; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAXIMUM_X_Y, sint16) = 5054; - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16) = 150; - RCT2_GLOBAL(0x01358836, sint16) = 4767; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16) = size * 32 - 32; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, sint16) = size * 32 - 2; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16) = size; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, sint16) = size * 32 - 33; RCT2_GLOBAL(0x01359208, sint16) = 7; map_update_tile_pointers(); RCT2_CALLPROC_EBPSAFE(0x0068ADBC); @@ -138,7 +272,7 @@ void map_init() */ void map_update_tile_pointers() { - int i, x, y, lastTile; + int i, x, y; for (i = 0; i < MAX_TILE_MAP_ELEMENT_POINTERS; i++) TILE_MAP_ELEMENT_POINTER(i) = TILE_UNDEFINED_MAP_ELEMENT; @@ -148,10 +282,7 @@ void map_update_tile_pointers() for (y = 0; y < 256; y++) { for (x = 0; x < 256; x++) { *tile++ = mapElement; - do { - lastTile = (mapElement->flags & MAP_ELEMENT_FLAG_LAST_TILE); - mapElement++; - } while (!lastTile); + do { } while (!map_element_is_last_for_tile(mapElement++)); } } @@ -341,7 +472,7 @@ void sub_68B089() mapElement++; mapElementFirst++; - } while (!((mapElement - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement - 1)); // Update next free element? mapElement = RCT2_GLOBAL(0x0140E9A4, rct_map_element*); @@ -357,43 +488,32 @@ void sub_68B089() * Checks if the tile at coordinate at height counts as connected. * @return 1 if connected, 0 otherwise */ -int map_coord_is_connected(uint16 tile_idx, uint8 height, uint8 face_direction) +int map_coord_is_connected(int x, int y, int z, uint8 faceDirection) { - rct_map_element* tile = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[tile_idx]; + rct_map_element *mapElement = map_get_first_element_at(x, y); - do { - rct_map_element_path_properties props = tile->properties.path; - uint8 path_type = props.type >> 2, path_dir = props.type & 3; - uint8 element_type = tile->type & MAP_ELEMENT_TYPE_MASK; + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; - if (element_type != PATH_ROAD) - continue; + rct_map_element_path_properties props = mapElement->properties.path; + uint8 pathType = props.type >> 2; + uint8 pathDirection = props.type & 3; - if (path_type & 1) { - if (path_dir == face_direction) { - if (height == tile->base_height + 2) + if (pathType & 1) { + if (pathDirection == faceDirection) { + if (z == mapElement->base_height + 2) return 1; - } - else if ((path_dir ^ 2) == face_direction && height == tile->base_height) { + } else if ((pathDirection ^ 2) == faceDirection && z == mapElement->base_height) { return 1; } - } else { - if (height == tile->base_height) + } else { + if (z == mapElement->base_height) return 1; - } - - } while (!(tile->flags & MAP_ELEMENT_FLAG_LAST_TILE) && tile++); + } + } while (!map_element_is_last_for_tile(mapElement++)); - return 0; -} - -/** - * - * rct2: 0x0068AFAD - */ -void map_invalidate_animations() -{ - RCT2_CALLPROC_EBPSAFE(0x0068AFAD); + return 0; } /** @@ -437,11 +557,16 @@ static void sub_6A87BB(int x, int y) RCT2_CALLPROC_X(0x006A87BB, x, 0, y, 0, 0, 0, 0); } -/* rct2: 0x6A7B84 */ -int map_height_from_slope(int x, int y, int slope){ - if (!(slope & 4)) return 0; +/** + * + * rct2: 0x006A7B84 + */ +int map_height_from_slope(int x, int y, int slope) +{ + if (!(slope & 4)) + return 0; - switch (slope & 3){ + switch (slope & 3) { case 0: return (31 - (x & 31)) / 2; case 1: @@ -458,16 +583,16 @@ int map_height_from_slope(int x, int y, int slope){ * * rct2: 0x00664F72 */ -int sub_664F72(int x, int y, int z) +int map_is_location_owned(int x, int y, int z) { rct_map_element *mapElement; if (x < (256 * 32) && y < (256 * 32)) { mapElement = map_get_surface_element_at(x / 32, y / 32); - if (mapElement->properties.surface.ownership & 0x20) + if (mapElement->properties.surface.ownership & OWNERSHIP_OWNED) return 1; - if (mapElement->properties.surface.ownership & 0x10) { + if (mapElement->properties.surface.ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED) { z /= 8; if (z < mapElement->base_height || z - 2 > mapElement->base_height) return 1; @@ -488,8 +613,8 @@ int map_is_location_in_park(int x, int y) if (x < (256 * 32) && y < (256 * 32)) { mapElement = map_get_surface_element_at(x / 32, y / 32); - if (mapElement->properties.surface.ownership & 0x20) - return 1; + if (mapElement->properties.surface.ownership & OWNERSHIP_OWNED) + return 1; } RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1729; @@ -510,66 +635,502 @@ void map_invalidate_tile(int x, int y, int zLow, int zHigh) * * rct2: 0x006E0E01 */ -money32 map_try_clear_scenery(int x, int y, rct_map_element *mapElement, int flags) +void game_command_remove_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { + int x = *eax; + int y = *ecx; + uint8 base_height = *edx; + uint8 scenery_type = *edx >> 8; + uint8 map_element_type = *ebx >> 8; money32 cost; - rct_scenery_entry *entry; - - entry = g_smallSceneryEntries[mapElement->properties.scenery.type]; + + rct_scenery_entry *entry = g_smallSceneryEntries[scenery_type]; cost = entry->small_scenery.removal_price * 10; - RCT2_GLOBAL(0x0141F56C, uint8) = 12; - RCT2_GLOBAL(0x009DEA5E, uint32) = x * 32 + 16; - RCT2_GLOBAL(0x009DEA60, uint32) = y * 32 + 16; - RCT2_GLOBAL(0x009DEA62, uint32) = mapElement->base_height * 8; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(0x009DEA5E, uint32) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint32) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint32) = base_height * 8; - x *= 32; - y *= 32; - - if (!(flags & 0x40) && RCT2_GLOBAL(0x009DEA6E, uint8) != 0) { + if (!(*ebx & 0x40) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - return MONEY32_UNDEFINED; + *ebx = MONEY32_UNDEFINED; + return; } - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & 0x40)) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !(*ebx & 0x40) && !gSandboxMode) { // Check if allowed to remove item if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_TREE_REMOVAL) { if (entry->small_scenery.height > 64) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; - return MONEY32_UNDEFINED; + *ebx = MONEY32_UNDEFINED; + return; } } // Check if the land is owned - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR)) - if (!sub_664F72(x, y, RCT2_GLOBAL(0x009DEA62, uint32))) - return MONEY32_UNDEFINED; + if (!map_is_location_owned(x, y, RCT2_GLOBAL(0x009DEA62, uint32))){ + *ebx = MONEY32_UNDEFINED; + return; + } } - if ((flags & 0x40) && !(mapElement->flags & 0x10)) - return 0; + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element->type != map_element_type || + map_element->base_height != base_height || + map_element->properties.scenery.type != scenery_type || + (*ebx & 0x40) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + *ebx = 0; + return; + } + } // Remove element - if (flags & 1) { + if (*ebx & GAME_COMMAND_FLAG_APPLY) { map_invalidate_tile_full(x, y); - map_element_remove(mapElement); + map_element_remove(map_element); } - return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : cost; + *ebx = (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : cost); } /** * - * rct2: 0x006E5597 + * rct2: 0x006B8E1B */ -money32 sub_6E5597(int x, int y, int dl, int dh, int bl) +void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x * 32; - ecx = y * 32; - ebx = bl & 0xFF; - edx = ((dh & 0xFF) << 8) | (dl & 0xFF); - RCT2_CALLFUNC_X(0x006E5597, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return ebx; + uint8 base_height = *edx; + uint8 scenerymultiple_index = *edx >> 8; + uint8 map_element_direction = *ebx >> 8; + int x = *eax; + int y = *ecx; + int z = map_element_height(x, y); + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + + if (!(*ebx & 0x40) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + } + + uint8 element_found = 0; + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) + continue; + + if (map_element->base_height != base_height) + continue; + + if ((map_element->properties.scenerymultiple.type >> 10) != scenerymultiple_index) + continue; + + if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != map_element_direction) + continue; + + element_found = 1; + break; + } while (!map_element_is_last_for_tile(map_element++)); + + if (!element_found){ + *ebx = 0; + return; + } + + if((*ebx & 0x40) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ + *ebx = 0; + return; + } + + map_element_remove_banner_entry(map_element); + + int ecx2 = map_element->properties.scenerymultiple.type >> 10; + rct_scenery_entry* scenery_entry = g_largeSceneryEntries[map_element->properties.scenerymultiple.type & 0x3FF]; + rct_xyz16 firstTile = { + .x = scenery_entry->large_scenery.tiles[ecx2].x_offset, + .y = scenery_entry->large_scenery.tiles[ecx2].y_offset, + .z = (base_height * 8) - scenery_entry->large_scenery.tiles[ecx2].z_offset + }; + + rotate_map_coordinates(&firstTile.x, &firstTile.y, map_element_direction); + + firstTile.x = x - firstTile.x; + firstTile.y = y - firstTile.y; + + for (int i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++){ + + rct_xyz16 currentTile = { + .x = scenery_entry->large_scenery.tiles[i].x_offset, + .y = scenery_entry->large_scenery.tiles[i].y_offset, + .z = scenery_entry->large_scenery.tiles[i].z_offset + }; + + rotate_map_coordinates(¤tTile.x, ¤tTile.y, map_element_direction); + + currentTile.x += firstTile.x; + currentTile.y += firstTile.y; + currentTile.z += firstTile.z; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode){ + if (!map_is_location_owned(currentTile.x, currentTile.y, currentTile.z)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + + // If not applying then no need to delete the actual element + if (!(*ebx & GAME_COMMAND_FLAG_APPLY)) + continue; + + rct_map_element* sceneryElement = map_get_first_element_at(currentTile.x / 32, currentTile.y / 32); + uint8 tile_not_found = 1; + do + { + if (map_element_get_type(sceneryElement) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) + continue; + + if ((sceneryElement->type & MAP_ELEMENT_DIRECTION_MASK) != map_element_direction) + continue; + + if ((sceneryElement->properties.scenerymultiple.type >> 10) != i) + continue; + + if (sceneryElement->base_height != currentTile.z / 8) + continue; + + map_invalidate_tile_full(currentTile.x, currentTile.y); + map_element_remove(sceneryElement); + tile_not_found = 0; + break; + } while (!map_element_is_last_for_tile(sceneryElement++)); + + if (tile_not_found){ + log_error("Tile not found when trying to remove element!"); + } + } + + *ebx = scenery_entry->large_scenery.removal_price * 10; + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + return; +} + +/** + * + * rct2: 0x006BA058 + */ +void game_command_remove_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + int x = *eax; + int y = *ecx; + uint8 base_height = *edx; + uint8 banner_position = *edx >> 8; + int z = base_height * 8; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + if(!(*ebx & 0x40) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + } + if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode && !map_is_location_owned(x, y, z - 16)){ + *ebx = MONEY32_UNDEFINED; + return; + } + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element->type != MAP_ELEMENT_TYPE_BANNER || + map_element->properties.banner.position != banner_position){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + rct_banner *banner = &gBanners[map_element->properties.banner.index]; + uint8 bannerType = banner->type; + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + map_element_remove_banner_entry(map_element); + map_invalidate_tile(x, y, z, z + 32); + map_element_remove(map_element); + } + rct_scenery_entry *scenery_entry = (rct_scenery_entry*)object_entry_groups[OBJECT_TYPE_BANNERS].chunks[bannerType]; + *ebx = (scenery_entry->banner.price * -3) / 4; + if(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } +} + +/** + * + * rct2: 0x006E0F26 + */ +void game_command_set_scenery_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + int x = *eax; + int y = *ecx; + uint8 base_height = *edx; + uint8 scenery_type = *edx >> 8; + uint8 map_element_type = *ebx >> 8; + uint8 color1 = *ebp; + uint8 color2 = *ebp >> 8; + int z = base_height * 8; + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode){ + if (!map_is_location_owned(x, y, z)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element->type != map_element_type || + map_element->base_height != base_height || + map_element->properties.scenery.type != scenery_type){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + *ebx = 0; + return; + } + } + if((*ebx & 0x40) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ + *ebx = 0; + return; + } + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + map_element->properties.scenery.colour_1 &= 0xE0; + map_element->properties.scenery.colour_1 |= color1; + map_element->properties.scenery.colour_2 &= 0xE0; + map_element->properties.scenery.colour_2 |= color2; + map_invalidate_tile_full(x, y); + } + + *ebx = 0; +} + +/** + * + * rct2: 0x006E56B5 + */ +void game_command_set_fence_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + int x = *eax; + int y = *ecx; + uint8 map_element_direction = *edx; + uint8 base_height = *edx >> 8; + uint8 color1 = *ebx >> 8; + uint8 color2 = *ebp; + uint8 color3 = *ebp >> 8; + int z = base_height * 8; + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + if((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || map_is_location_in_park(x, y) || gSandboxMode){ + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element_get_type(map_element) != MAP_ELEMENT_TYPE_FENCE || + map_element->base_height != base_height || + (map_element->type & MAP_ELEMENT_DIRECTION_MASK) != map_element_direction|| + ((*ebx & 0x40) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST))){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + *ebx = 0; + return; + } + } + if((*ebx & 0x40) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ + *ebx = 0; + return; + } + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + rct_scenery_entry* scenery_entry = RCT2_ADDRESS(RCT2_ADDRESS_WALL_SCENERY_ENTRIES, rct_scenery_entry*)[map_element->properties.fence.type]; + map_element->properties.fence.item[1] &= 0xE0; + map_element->properties.fence.item[1] |= color1; + map_element->flags &= 0x9F; + map_element->properties.fence.item[1] &= 0x1F; + map_element->properties.fence.item[1] |= (color2 & 0x7) * 32; + map_element->flags |= (color2 & 0x18) * 4; + if(scenery_entry->wall.flags & 0x80){ + map_element->properties.fence.item[0] = color3; + } + map_invalidate_tile(x, y, z, z + 0x48); + } + *ebx = 0; + } else { + *ebx = MONEY32_UNDEFINED; + } +} + +/** + * + * rct2: 0x006B909A + */ +void game_command_set_large_scenery_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + int x = *eax; + int y = *ecx; + uint8 map_element_direction = *ebx >> 8; + uint8 base_height = *edx; + uint8 scenerymultiple_index = *edx >> 8; + uint8 color1 = *ebp; + uint8 color2 = *ebp >> 8; + int z = map_element_height(x, y); + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + + + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE || + map_element->base_height != base_height || + map_element->properties.scenerymultiple.type >> 10 != scenerymultiple_index || + (map_element->type & MAP_ELEMENT_DIRECTION_MASK) != map_element_direction){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + *ebx = 0; + return; + } + } + if((*ebx & 0x40) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ + *ebx = 0; + return; + } + int ecx2 = map_element->properties.scenerymultiple.type >> 10; + rct_scenery_entry* scenery_entry = RCT2_ADDRESS(RCT2_ADDRESS_LARGE_SCENERY_ENTRIES, rct_scenery_entry*)[map_element->properties.scenerymultiple.type & 0x3FF]; + int x2 = scenery_entry->large_scenery.tiles[ecx2].x_offset; + int y2 = scenery_entry->large_scenery.tiles[ecx2].y_offset; + int z2 = (base_height * 8) - scenery_entry->large_scenery.tiles[ecx2].z_offset; + switch(map_element->type & MAP_ELEMENT_DIRECTION_MASK){ + case MAP_ELEMENT_DIRECTION_WEST: + break; + case MAP_ELEMENT_DIRECTION_NORTH:{ + int temp = x2; + x2 = y2; + y2 = -temp; + }break; + case MAP_ELEMENT_DIRECTION_EAST: + x2 = -x2; + y2 = -y2; + break; + case MAP_ELEMENT_DIRECTION_SOUTH:{ + int temp = y2; + y2 = x2; + x2 = -temp; + }break; + } + x2 = -x2 + x; + y2 = -y2 + y; + int i = 0; + while(1){ + if(scenery_entry->large_scenery.tiles[i].x_offset == -1){ + *ebx = 0; + return; + } + int x3 = scenery_entry->large_scenery.tiles[i].x_offset; + int y3 = scenery_entry->large_scenery.tiles[i].y_offset; + int z3 = scenery_entry->large_scenery.tiles[i].z_offset; + switch(map_element->type & MAP_ELEMENT_DIRECTION_MASK){ + case MAP_ELEMENT_DIRECTION_WEST: + break; + case MAP_ELEMENT_DIRECTION_NORTH:{ + int temp = x3; + x3 = y3; + y3 = -temp; + }break; + case MAP_ELEMENT_DIRECTION_EAST: + x3 = -x3; + y3 = -y3; + break; + case MAP_ELEMENT_DIRECTION_SOUTH:{ + int temp = y3; + y3 = x3; + x3 = -temp; + }break; + } + x3 += x2; + y3 += y2; + z3 += z2; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode){ + if (!map_is_location_owned(x3, y3, z3)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + rct_map_element* map_element = map_get_first_element_at(x3 / 32, y3 / 32); + while(map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE || + (map_element->type & MAP_ELEMENT_DIRECTION_MASK) != map_element_direction || + map_element->properties.scenerymultiple.type >> 10 != i || + map_element->base_height != base_height){ + map_element++; + } + map_element->properties.scenerymultiple.colour[0] &= 0xE0; + map_element->properties.scenerymultiple.colour[0] |= color1; + map_element->properties.scenerymultiple.colour[1] &= 0xE0; + map_element->properties.scenerymultiple.colour[1] |= color2; + map_invalidate_tile_full(x3, y3); + } + + i++; + } + *ebx = 0; +} + +/** + * + * rct2: 0x006BA16A + */ +void game_command_set_banner_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + int x = *eax; + int y = *ecx; + uint8 base_height = *edx; + uint8 banner_position = *edx >> 8; + uint8 color = *ebp; + int z = (base_height * 8); + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode){ + if (!map_is_location_owned(x, y, z - 16)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element->type != MAP_ELEMENT_TYPE_BANNER || + map_element->properties.banner.position != banner_position){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + rct_window* window = window_find_by_number(WC_BANNER, map_element->properties.banner.index); + if(window){ + window_invalidate(window); + } + gBanners[map_element->properties.banner.index].colour = color; + map_invalidate_tile(x, y, z, z + 32); + } + + *ebx = 0; } money32 sub_6A67C0(int x, int y, int z, int flags) @@ -600,43 +1161,77 @@ money32 map_clear_scenery_from_tile(int x, int y, int flags) totalCost = 0; restart_from_beginning: - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + mapElement = map_get_first_element_at(x, y); do { - type = mapElement->type & MAP_ELEMENT_TYPE_MASK; + type = map_element_get_type(mapElement); switch (type) { case MAP_ELEMENT_TYPE_PATH: -#ifdef CLEAR_SCENERY_REMOVES_PATHS - cost = sub_6A67C0(x, y, mapElement->base_height, flags); - if (cost == MONEY32_UNDEFINED) - return MONEY32_UNDEFINED; + if (gClearFootpath) { + cost = sub_6A67C0(x, y, mapElement->base_height, flags); + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; - totalCost += cost; - if (flags & 1) - goto restart_from_beginning; -#endif - break; + totalCost += cost; + if (flags & 1) + goto restart_from_beginning; + } break; case MAP_ELEMENT_TYPE_SCENERY: - cost = map_try_clear_scenery(x, y, mapElement, flags); - if (cost == MONEY32_UNDEFINED) - return MONEY32_UNDEFINED; + if (gClearSmallScenery) { + int eax = x * 32; + int ebx = (mapElement->type << 8) | flags; + int ecx = y * 32; + int edx = (mapElement->properties.scenery.type << 8) | (mapElement->base_height); + int esi, edi, ebp; + game_command_remove_scenery(&eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + cost = ebx; - totalCost += cost; - if (flags & 1) - goto restart_from_beginning; + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; - break; + totalCost += cost; + if (flags & 1) + goto restart_from_beginning; + + } break; case MAP_ELEMENT_TYPE_FENCE: - cost = sub_6E5597(x, y, mapElement->type & 3, mapElement->base_height, flags); - if (cost == MONEY32_UNDEFINED) - return MONEY32_UNDEFINED; + if (gClearSmallScenery) { + int eax = x * 32; + int ebx = flags; + int ecx = y * 32; + int edx = (mapElement->base_height << 8) | (mapElement->type & MAP_ELEMENT_DIRECTION_MASK); + int esi, edi, ebp; + game_command_remove_fence(&eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + cost = ebx; - totalCost += cost; - if (flags & 1) - goto restart_from_beginning; + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + totalCost += cost; + if (flags & 1) + goto restart_from_beginning; + + } break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + if (gClearLargeScenery) { + int eax = x * 32; + int ebx = flags | ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) << 8); + int ecx = y * 32; + int edx = mapElement->base_height | ((mapElement->properties.scenerymultiple.type >> 10) << 8); + int esi, edi, ebp; + game_command_remove_large_scenery(&eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + cost = ebx; + + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + totalCost += cost; + if (flags & 1) + goto restart_from_beginning; + + } break; break; } - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } while (!map_element_is_last_for_tile(mapElement++)); return totalCost; } @@ -646,7 +1241,7 @@ money32 map_clear_scenery(int x0, int y0, int x1, int y1, int flags) int x, y, z; money32 totalCost, cost; - RCT2_GLOBAL(0x0141F56C, uint8) = 12; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; x = (x0 + x1) / 2 + 16; y = (y0 + y1) / 2 + 16; @@ -655,15 +1250,15 @@ money32 map_clear_scenery(int x0, int y0, int x1, int y1, int flags) RCT2_GLOBAL(0x009DEA60, uint16) = y; RCT2_GLOBAL(0x009DEA62, uint16) = z; - x0 = clamp(0, x0, 255); - y0 = clamp(0, y0, 255); - x1 = clamp(0, x1, 255); - y1 = clamp(0, y1, 255); + x0 = max(x0, 32); + y0 = max(y0, 32); + x1 = min(x1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + y1 = min(y1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); totalCost = 0; - for (y = y0; y <= y1; y++) { - for (x = x0; x <= x1; x++) { - cost = map_clear_scenery_from_tile(x, y, flags); + for (y = y0; y <= y1; y += 32) { + for (x = x0; x <= x1; x += 32) { + cost = map_clear_scenery_from_tile(x / 32, y / 32, flags); if (cost == MONEY32_UNDEFINED) return MONEY32_UNDEFINED; @@ -681,14 +1276,1051 @@ money32 map_clear_scenery(int x0, int y0, int x1, int y1, int flags) void game_command_clear_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { *ebx = map_clear_scenery( - (*eax & 0xFFFF) / 32, - (*ecx & 0xFFFF) / 32, - (*edi & 0xFFFF) / 32, - (*ebp & 0xFFFF) / 32, + (sint16)(*eax & 0xFFFF), + (sint16)(*ecx & 0xFFFF), + (sint16)(*edi & 0xFFFF), + (sint16)(*ebp & 0xFFFF), *ebx & 0xFF ); } +/* rct2: 0x00663CCD */ +money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 surfaceStyle, uint8 edgeStyle, uint8 flags) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + + x0 = max(x0, 32); + y0 = max(y0, 32); + x1 = min(x1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + y1 = min(y1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + + int xMid, yMid; + + xMid = (x0 + x1) / 2 + 16; + yMid = (y0 + y1) / 2 + 16; + + int heightMid = map_element_height(xMid, yMid); + + RCT2_GLOBAL(0x009DEA5E, uint16) = xMid; + RCT2_GLOBAL(0x009DEA60, uint16) = yMid; + RCT2_GLOBAL(0x009DEA62, uint16) = heightMid; + RCT2_GLOBAL(0x009E32B4, uint32) = 0; + + money32 cost = 0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + cost += RCT2_GLOBAL(0x009E32B4, uint32); + return (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? 0 : cost; + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode && RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) { + cost += RCT2_GLOBAL(0x009E32B4, uint32); + return (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? 0 : cost; + } + + for (int x = x0; x <= x1; x += 32) { + for (int y = y0; y <= y1; y += 32) { + if (x > 0x1FFF) continue; + if (y > 0x1FFF) continue; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode) { + if (!map_is_location_in_park(x, y)) continue; + } + + rct_map_element* mapElement = map_get_surface_element_at(x / 32, y / 32); + + if (surfaceStyle != 0xFF){ + uint8 cur_terrain = ( + (mapElement->type&MAP_ELEMENT_DIRECTION_MASK) << 3) | + (mapElement->properties.surface.terrain >> 5); + + if (surfaceStyle != cur_terrain) { + RCT2_GLOBAL(0x009E32B4, uint32) += RCT2_ADDRESS(0x0097B8B8, uint32)[surfaceStyle & 0x1F]; + if (flags & 1){ + mapElement->properties.surface.terrain &= MAP_ELEMENT_WATER_HEIGHT_MASK; + mapElement->type &= MAP_ELEMENT_QUADRANT_MASK | MAP_ELEMENT_TYPE_MASK; + + //Save the new terrain + mapElement->properties.surface.terrain |= surfaceStyle << 5; + + //Save the new direction mask + mapElement->type |= (surfaceStyle >> 3) & MAP_ELEMENT_DIRECTION_MASK; + + map_invalidate_tile_full(x, y); + RCT2_CALLPROC_X(0x00673883, x, 0, y, map_element_height(x, y), 0, 0, 0); + } + } + } + + if (edgeStyle != 0xFF) { + uint8 currentEdge = + ((mapElement->type & 0x80) >> 4) | + (mapElement->properties.surface.slope >> 5); + + if (edgeStyle != currentEdge){ + cost++; + + if (flags & 1){ + mapElement->properties.surface.slope &= MAP_ELEMENT_SLOPE_MASK; + mapElement->type &= 0x7F; + + //Save edge style + mapElement->properties.surface.slope |= edgeStyle << 5; + + //Save ??? + mapElement->type |= (edgeStyle << 4) & 0x80; + map_invalidate_tile_full(x, y); + } + } + } + + if (flags & 1) { + if (!(mapElement->properties.surface.terrain & MAP_ELEMENT_SURFACE_TERRAIN_MASK)) { + if (!(mapElement->type & MAP_ELEMENT_DIRECTION_MASK)) { + if ((mapElement->properties.surface.grass_length & 7) != GRASS_LENGTH_CLEAR_0) { + mapElement->properties.surface.grass_length = GRASS_LENGTH_CLEAR_0; + map_invalidate_tile_full(x, y); + } + } + } + } + } + } + + cost *= 100; + cost += RCT2_GLOBAL(0x009E32B4, uint32); + return (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) ? 0 : cost; +} + +/* rct2: 0x00663CCD */ +void game_command_change_surface_style(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + *ebx = map_change_surface_style( + (sint16)(*eax & 0xFFFF), + (sint16)(*ecx & 0xFFFF), + (sint16)(*edi & 0xFFFF), + (sint16)(*ebp & 0xFFFF), + *edx & 0xFF, + (*edx & 0xFF00) >> 8, + *ebx & 0xFF + ); +} + +//0x00981A1E +const uint8 map_element_raise_styles[5][32] = { + { 0x01, 0x1B, 0x03, 0x1B, 0x05, 0x21, 0x07, 0x21, 0x09, 0x1B, 0x0B, 0x1B, 0x0D, 0x21, 0x20, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x23, 0x18, 0x19, 0x1A, 0x3B, 0x1C, 0x29, 0x24, 0x1F }, + { 0x02, 0x03, 0x17, 0x17, 0x06, 0x07, 0x17, 0x17, 0x0A, 0x0B, 0x22, 0x22, 0x0E, 0x20, 0x22, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x37, 0x18, 0x19, 0x1A, 0x23, 0x1C, 0x28, 0x26, 0x1F }, + { 0x04, 0x05, 0x06, 0x07, 0x1E, 0x24, 0x1E, 0x24, 0x0C, 0x0D, 0x0E, 0x20, 0x1E, 0x24, 0x1E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x26, 0x18, 0x19, 0x1A, 0x21, 0x1C, 0x2C, 0x3E, 0x1F }, + { 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x20, 0x1D, 0x1D, 0x28, 0x28, 0x1D, 0x1D, 0x28, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x22, 0x18, 0x19, 0x1A, 0x29, 0x1C, 0x3D, 0x2C, 0x1F }, + { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x21, 0x20, 0x28, 0x24, 0x20 }, +}; + +//0x00981ABE +const uint8 map_element_lower_styles[5][32] = { + { 0x2E, 0x00, 0x2E, 0x02, 0x3E, 0x04, 0x3E, 0x06, 0x2E, 0x08, 0x2E, 0x0A, 0x3E, 0x0C, 0x3E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x06, 0x18, 0x19, 0x1A, 0x0B, 0x1C, 0x0C, 0x3E, 0x1F }, + { 0x2D, 0x2D, 0x00, 0x01, 0x2D, 0x2D, 0x04, 0x05, 0x3D, 0x3D, 0x08, 0x09, 0x3D, 0x3D, 0x0C, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x07, 0x18, 0x19, 0x1A, 0x09, 0x1C, 0x3D, 0x0C, 0x1F }, + { 0x2B, 0x3B, 0x2B, 0x3B, 0x00, 0x01, 0x02, 0x03, 0x2B, 0x3B, 0x2B, 0x3B, 0x08, 0x09, 0x0A, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x03, 0x18, 0x19, 0x1A, 0x3B, 0x1C, 0x09, 0x0E, 0x1F }, + { 0x27, 0x27, 0x37, 0x37, 0x27, 0x27, 0x37, 0x37, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x37, 0x18, 0x19, 0x1A, 0x03, 0x1C, 0x0D, 0x06, 0x1F }, + { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x0D, 0x0E, 0x00 }, +}; + +static money32 sub_66397F(int flags, int x, int y, int height, int style, int selectionType) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode) { + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; + return MONEY32_UNDEFINED; + } + } + + if (x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) || y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_OFF_EDGE_OF_MAP; + return MONEY32_UNDEFINED; + } + + if (height < 2) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_LOW; + return MONEY32_UNDEFINED; + } + + if (height > 62) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } else if (height == 62 && (style & 0x1F) != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } + + if (height == 60 && (style & 0x10)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode) { + if (!map_is_location_in_park(x, y)) { + return MONEY32_UNDEFINED; + } + } + + int eax = x, ebx = flags, ecx = y, edx = (style << 8) | height, esi = 0, edi = selectionType << 5, ebp = 0; + RCT2_CALLFUNC_X(0x006639FE, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return ebx; +} + +money32 raise_land(int flags, int x, int y, int z, int ax, int ay, int bx, int by, int selectionType) +{ + money32 cost = 0; + + if ((flags & GAME_COMMAND_FLAG_APPLY) && RCT2_GLOBAL(0x009A8C28, uint8) == 1) { + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, x, y, z); + } + + uint8 min_height = 0xFF; + + ax = max(ax, 32); + ay = max(ay, 32); + bx = min(bx, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + by = min(by, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + + // find lowest map element in selection + for (int yi = ay; yi <= by; yi += 32) { + for (int xi = ax; xi <= bx; xi += 32) { + rct_map_element *map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL && min_height > map_element->base_height) { + min_height = map_element->base_height; + } + } + } + + for (int yi = ay; yi <= by; yi += 32) { + for (int xi = ax; xi <= bx; xi += 32) { + rct_map_element *map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL) { + uint8 height = map_element->base_height; + if (height <= min_height){ + uint8 newStyle = map_element_raise_styles[selectionType][map_element->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK]; + if (newStyle & 0x20) { // needs to be raised + height += 2; + newStyle &= ~0x20; + } + money32 tileCost = sub_66397F(flags, xi, yi, height, newStyle, selectionType); + if (tileCost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + cost += tileCost; + } + } + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint32) = x; + RCT2_GLOBAL(0x009DEA60, uint32) = y; + RCT2_GLOBAL(0x009DEA62, uint32) = z; + return cost; +} + +money32 lower_land(int flags, int x, int y, int z, int ax, int ay, int bx, int by, int selectionType) +{ + money32 cost = 0; + + if ((flags & GAME_COMMAND_FLAG_APPLY) && RCT2_GLOBAL(0x009A8C28, uint8) == 1) { + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, x, y, z); + } + + uint8 max_height = 0; + + ax = max(ax, 32); + ay = max(ay, 32); + bx = min(bx, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + by = min(by, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + + // find highest map element in selection + for (int yi = ay; yi <= by; yi += 32) { + for (int xi = ax; xi <= bx; xi += 32) { + rct_map_element *map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL) { + uint8 base_height = map_element->base_height; + if (map_element->properties.surface.slope & 0xF) + base_height += 2; + if (map_element->properties.surface.slope & 0x10) + base_height += 2; + if (max_height < base_height) + max_height = base_height; + } + } + } + + for (int yi = ay; yi <= by; yi += 32) { + for (int xi = ax; xi <= bx; xi += 32) { + rct_map_element *map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL) { + uint8 height = map_element->base_height; + if (map_element->properties.surface.slope & 0xF) + height += 2; + if (map_element->properties.surface.slope & 0x10) + height += 2; + if (height >= max_height) { + height = map_element->base_height; + uint8 newStyle = map_element_lower_styles[selectionType][map_element->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK]; + if (newStyle & 0x20) { // needs to be lowered + height -= 2; + newStyle &= ~0x20; + } + money32 tileCost = sub_66397F(flags, xi, yi, height, newStyle, selectionType); + if (tileCost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + cost += tileCost; + } + } + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + RCT2_GLOBAL(0x009DEA5E, uint32) = x; + RCT2_GLOBAL(0x009DEA60, uint32) = y; + RCT2_GLOBAL(0x009DEA62, uint32) = z; + return cost; +} + +money32 raise_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags) +{ + money32 cost = 0; + + uint8 max_height = 0xFF; + + x0 = max(x0, 32); + y0 = max(y0, 32); + x1 = min(x1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + y1 = min(y1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + + for (int yi = y0; yi <= y1; yi += 32) { + for (int xi = x0; xi <= x1; xi += 32) { + rct_map_element* map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL) { + uint8 height = map_element->base_height; + if (map_element->properties.surface.terrain & 0x1F) + height = (map_element->properties.surface.terrain & 0x1F) * 2; + if (max_height > height) + max_height = height; + } + } + } + + for (int yi = y0; yi <= y1; yi += 32) { + for (int xi = x0; xi <= x1; xi += 32) { + rct_map_element* map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL) { + if (map_element->base_height <= max_height){ + uint8 height = (map_element->properties.surface.terrain & 0x1F); + if (height != 0) { + height *= 2; + if (height > max_height) + continue; + height += 2; + } else { + height = map_element->base_height + 2; + } + + money32 tileCost = game_do_command(xi, flags, yi, (max_height << 8) + height, GAME_COMMAND_16, 0, 0); + if (tileCost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + cost += tileCost; + } + } + } + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + int x = ((x0 + x1) / 2) + 16; + int y = ((y0 + y1) / 2) + 16; + int z = map_element_height(x, y); + sint16 water_height_z = z >> 16; + sint16 base_height_z = z; + z = water_height_z; + if (z != 0) + z = base_height_z; + RCT2_GLOBAL(0x009DEA5E, uint32) = x; + RCT2_GLOBAL(0x009DEA60, uint32) = y; + RCT2_GLOBAL(0x009DEA62, uint32) = z; + sound_play_panned(SOUND_LAYING_OUT_WATER, 0x8001, x, y, z); + } + + return cost; +} + +money32 lower_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags) +{ + money32 cost = 0; + + uint8 min_height = 0; + + x0 = max(x0, 32); + y0 = max(y0, 32); + x1 = min(x1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + y1 = min(y1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16)); + + for (int yi = y0; yi <= y1; yi += 32){ + for (int xi = x0; xi <= x1; xi += 32){ + rct_map_element* map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL) { + uint8 height = map_element->properties.surface.terrain & 0x1F; + if (height != 0) { + height *= 2; + if (height > min_height) + min_height = height; + } + } + } + } + + for (int yi = y0; yi <= y1; yi += 32) { + for (int xi = x0; xi <= x1; xi += 32) { + rct_map_element* map_element = map_get_surface_element_at(xi / 32, yi / 32); + if (map_element != NULL) { + uint8 height = (map_element->properties.surface.terrain & 0x1F); + if (height != 0) { + height *= 2; + if (height < min_height) + continue; + height -= 2; + int tileCost = game_do_command(xi, flags, yi, (min_height << 8) + height, GAME_COMMAND_16, 0, 0); + if (tileCost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + cost += tileCost; + } + } + } + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + int x = ((x0 + x1) / 2) + 16; + int y = ((y0 + y1) / 2) + 16; + int z = map_element_height(x, y); + sint16 water_height_z = z >> 16; + sint16 base_height_z = z; + z = water_height_z; + if (z == 0) + z = base_height_z; + RCT2_GLOBAL(0x009DEA5E, uint32) = x; + RCT2_GLOBAL(0x009DEA60, uint32) = y; + RCT2_GLOBAL(0x009DEA62, uint32) = z; + sound_play_panned(SOUND_LAYING_OUT_WATER, 0x8001, x, y, z); + } + + return cost; +} + +/** + * + * rct2: 0x0068C542 + */ +void game_command_raise_land(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + *ebx = raise_land( + *ebx, + *eax, + *ecx, + map_element_height(*eax, *ecx), + (sint16)(*edx & 0xFFFF), + (sint16)(*ebp & 0xFFFF), + *edx >> 16, + *ebp >> 16, + *edi & 0xFFFF + ); +} + +/** + * + * rct2: 0x0068C6D1 + */ +void game_command_lower_land(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + *ebx = lower_land( + *ebx, + *eax, + *ecx, + map_element_height(*eax, *ecx), + (sint16)(*edx & 0xFFFF), + (sint16)(*ebp & 0xFFFF), + *edx >> 16, + *ebp >> 16, + *edi & 0xFFFF + ); +} + +/** + * + * rct2: 0x006E66A0 + */ +void game_command_raise_water(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + *ebx = raise_water( + (sint16)(*eax & 0xFFFF), + (sint16)(*ecx & 0xFFFF), + (sint16)(*edi & 0xFFFF), + (sint16)(*ebp & 0xFFFF), + (uint8)*ebx + ); +} + +/** + * + * rct2: 0x006E6878 + */ +void game_command_lower_water(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + *ebx = lower_water( + (sint16)(*eax & 0xFFFF), + (sint16)(*ecx & 0xFFFF), + (sint16)(*edi & 0xFFFF), + (sint16)(*ebp & 0xFFFF), + (uint8)*ebx + ); +} + +/** + * + * rct2: 0x006E5597 + */ +void game_command_remove_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + int x = *eax; + int y = *ecx; + uint8 base_height = (*edx >> 8); + uint8 direction = *edx; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + if(!(*ebx & 0x40) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + } + if(!(*ebx & 0x40) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode && !map_is_location_owned(x, y, base_height * 8)){ + *ebx = MONEY32_UNDEFINED; + return; + } + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element_get_type(map_element) != MAP_ELEMENT_TYPE_FENCE || + map_element->base_height != base_height || + (map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction || + ((*ebx & 0x40) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST))){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + *ebx = 0; + return; + } + } + + if (!(*ebx & GAME_COMMAND_FLAG_APPLY)){ + *ebx = 0; + return; + } + + map_element_remove_banner_entry(map_element); + map_invalidate_tile(x, y, map_element->base_height * 8, (map_element->base_height * 8) + 72); + map_element_remove(map_element); + *ebx = 0; +} + +/** + * + * rct2: 0x006B9E6D + */ +void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + int x = (uint16)*eax; + int y = (uint16)*ecx; + uint8 base_height = *edx; + uint8 edge = *edx >> 8; + uint8 colour = *edi; + uint8 type = *ebx >> 8; + RCT2_GLOBAL(0x009DEA5E, uint32) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint32) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint32) = base_height * 16; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + if(RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0 || gConfigCheat.build_in_pause_mode){ + if(sub_68B044() && x < 8192 && y < 8192){ + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + int dl = base_height * 2; + int ch = (base_height - 1) * 2; + while(map_element_get_type(map_element) != MAP_ELEMENT_TYPE_PATH || + (map_element->base_height != dl && map_element->base_height != ch) || + !(map_element->properties.path.edges & (1 << edge))){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CAN_ONLY_BE_BUILT_ACROSS_PATHS; + *ebx = MONEY32_UNDEFINED; + return; + } + } + if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode && !map_is_location_owned(x, y, base_height * 16)){ + *ebx = MONEY32_UNDEFINED; + return; + } + map_element = map_get_first_element_at(x / 32, y / 32); + dl = (base_height + 1) * 2; + while(map_element->type != MAP_ELEMENT_TYPE_BANNER || + map_element->base_height != dl || + (map_element->properties.banner.position & 0x3) != edge){ + map_element++; + if((map_element - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE){ + int banner_index = create_new_banner(*ebx); + if(banner_index == BANNER_NULL){ + *ebx = MONEY32_UNDEFINED; + return; + } + *edi = banner_index; + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + rct_map_element* new_map_element = map_element_insert(x / 32, y / 32, (base_height + 1) * 2, 0); + gBanners[banner_index].type = type; + gBanners[banner_index].colour = colour; + gBanners[banner_index].x = x / 32; + gBanners[banner_index].y = y / 32; + new_map_element->type = MAP_ELEMENT_TYPE_BANNER; + new_map_element->clearance_height = new_map_element->base_height + 2; + new_map_element->properties.banner.position = edge; + new_map_element->properties.banner.flags = 0xFF; + new_map_element->properties.banner.unused = 0; + new_map_element->properties.banner.index = banner_index; + if(*ebx & 0x40){ + new_map_element->flags |= 0x10; + } + map_invalidate_tile_full(x, y); + map_animation_create(0x0A, x, y, new_map_element->base_height); + } + rct_scenery_entry *scenery_entry = (rct_scenery_entry*)object_entry_groups[OBJECT_TYPE_BANNERS].chunks[type]; + *ebx = scenery_entry->banner.price; + if(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + return; + } + } + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BANNER_SIGN_IN_THE_WAY; + *ebx = MONEY32_UNDEFINED; + return; + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + } + *ebx = MONEY32_UNDEFINED; +} + +/** + * + * rct2: 0x006E08F4 + */ +void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + int x = (uint16)*eax; + int y = (uint16)*ecx; + uint8 color2 = *edi >> 16; + uint8 rotation = *edi; + int z = *ebp; + uint8 scenery_type = *ebx >> 8; + uint8 quadrant = *edx; + uint8 color1 = *edx >> 8; + int F64F1D = 0; + int F64EC8 = z; + int base_height = map_element_height(x, y); + if(base_height & 0xFFFF0000){ + base_height >>= 16; + } + RCT2_GLOBAL(0x009DEA5E, uint16) = x; + RCT2_GLOBAL(0x009DEA60, uint16) = y; + RCT2_GLOBAL(0x009DEA62, uint16) = base_height; + if(F64EC8){ + base_height = F64EC8; + RCT2_GLOBAL(0x009DEA62, uint16) = base_height; + } + RCT2_GLOBAL(0x009DEA5E, uint16) += 16; + RCT2_GLOBAL(0x009DEA60, uint16) += 16; + if(RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0 || gConfigCheat.build_in_pause_mode){ + if(sub_68B044()){ + if(RCT2_GLOBAL(0x009D8150, uint8) & 1 || (x <= RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) && y <= RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16))){ + rct_scenery_entry* scenery_entry = (rct_scenery_entry*)object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].chunks[scenery_type]; + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE || !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9)){ + if(scenery_entry->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25)){ + quadrant = 0; + } + } + int x2 = x; + int y2 = y; + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ + x2 += 16; + y2 += 16; + }else{ + x2 += RCT2_ADDRESS(0x009A3E74, uint8)[(quadrant & 3) * 2] - 1; + y2 += RCT2_ADDRESS(0x009A3E75, uint8)[(quadrant & 3) * 2] - 1; + } + int base_height2 = map_element_height(x2, y2); + if(base_height2 & 0xFFFF0000){ + base_height2 >>= 16; + if(F64EC8 == 0){ + F64F1D = 1; + } + } + if(F64EC8 == 0){ + F64EC8 = base_height2; + } + if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode && !map_is_location_owned(x, y, F64EC8)){ + *ebx = MONEY32_UNDEFINED; + return; + } + if(*ebx & GAME_COMMAND_FLAG_APPLY && !(*ebx & 0x40)){ + footpath_remove_litter(x, y, F64EC8); + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG19){ + RCT2_CALLPROC_X(0x006E588E, x, scenery_entry->small_scenery.height, y, F64EC8, 0, 0, 0); + } + } + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + while(map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SURFACE){ + map_element++; + } + if(map_element->properties.surface.terrain & 0x1F){ + int water_height = ((map_element->properties.surface.terrain & 0x1F) * 16) - 1; + if(water_height > F64EC8){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CANT_BUILD_THIS_UNDERWATER; + *ebx = MONEY32_UNDEFINED; + return; + } + } + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18)){ + if(F64F1D != 0){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + *ebx = MONEY32_UNDEFINED; + return; + } + if(map_element->properties.surface.terrain & 0x1F){ + if(((map_element->properties.surface.terrain & 0x1F) * 16) > F64EC8){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + *ebx = MONEY32_UNDEFINED; + return; + } + } + } + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE) || z != 0 || F64F1D != 0 || !(map_element->properties.surface.slope & 0x1F)){ + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18 || z == 0){ + l_6E0B78: ; + int bp = quadrant; + int zLow = F64EC8 / 8; + int zHigh = zLow + ((scenery_entry->small_scenery.height + 7) / 8); + int bl = 0xF; + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ + bp ^= 2; + bl = 1; + bl <<= bp; + } + if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG24)){ + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9 && scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG25){ + bp ^= 2; + bp += rotation; + bp &= 3; + bl = 0xBB; + bl = rol8(bl, bp); + bl &= 0xF; + }else{ + bp += rotation; + bp &= 1; + bl = 0xA; + bl >>= bp; + } + } + }else{ + bp ^= 2; + bp += rotation; + bp &= 3; + bl = 0x33; + bl = rol8(bl, bp); + bl &= 0xF; + } + if(z == 0){ + bl |= 0xF0; + } + RCT2_GLOBAL(0x00F64F22, uint16) = x; + RCT2_GLOBAL(0x00F64F24, uint16) = y; + RCT2_GLOBAL(0x00F64F1E, uint32) = (uint32)(ebx - 1); //0x006E0D6E uses [F64F1E+4] to read ebx value + if(map_can_construct_with_clear_at(x, y, zLow, zHigh, (void*)0x006E0D6E, bl)){ + RCT2_GLOBAL(0x00F64F14, uint8) = RCT2_GLOBAL(0x00F1AD60, uint8) & 0x3; + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + int flags = (bl & 0xf); + rct_map_element* new_map_element = map_element_insert(x / 32, y / 32, zLow, flags); + RCT2_GLOBAL(0x00F64EBC, rct_map_element*) = new_map_element; + uint8 type = quadrant << 6; + type |= MAP_ELEMENT_TYPE_SCENERY; + type |= rotation; + new_map_element->type = type; + new_map_element->properties.scenery.type = scenery_type; + new_map_element->properties.scenery.age = 0; + new_map_element->properties.scenery.colour_1 = color1; + new_map_element->properties.scenery.colour_2 = color2; + new_map_element->clearance_height = new_map_element->base_height + ((scenery_entry->small_scenery.height + 7) / 8); + if(z != 0){ + new_map_element->properties.scenery.colour_1 |= 0x20; + } + if(*ebx & 0x40){ + new_map_element->flags |= 0x10; + } + map_invalidate_tile_full(x, y); + if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED){ + map_animation_create(2, x, y, new_map_element->base_height); + } + } + *ebx = (scenery_entry->small_scenery.price * 10); + if(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + return; + } + }else{ + if(F64F1D == 0){ + if((map_element->properties.surface.terrain & 0x1F) || (map_element->base_height * 8) != F64EC8){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_LEVEL_LAND_REQUIRED; + }else{ + goto l_6E0B78; + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + } + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_LEVEL_LAND_REQUIRED; + } + } + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + } + *ebx = MONEY32_UNDEFINED; +} + +/** + * + * rct2: 0x006B893C + */ +void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + int x = (sint16)*eax; + int y = (sint16)*ecx; + int z = (sint16)*ebp; + uint8 color1 = *edx; + uint8 color2 = *edx >> 8; + uint8 flags = *ebx; + uint8 rotation = *ebx >> 8; + uint8 entry_index = *edi; + int base_height = map_element_height(x, y); + RCT2_GLOBAL(0x009DEA5E, sint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, sint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, sint16) = base_height; + RCT2_GLOBAL(0x00F64F14, uint8) = 0; + uint8 banner_id = 0xFF; + RCT2_GLOBAL(0x00F4389A, uint32) = 0; + if(RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0 || gConfigCheat.build_in_pause_mode){ + if(sub_68B044()){ + rct_scenery_entry* scenery_entry = RCT2_ADDRESS(RCT2_ADDRESS_LARGE_SCENERY_ENTRIES, rct_scenery_entry*)[entry_index]; + if(scenery_entry->large_scenery.var_11 != 0xFF){ + banner_id = create_new_banner(flags); + if(banner_id == MAX_BANNERS){ + *ebx = MONEY32_UNDEFINED; + return; + } + if(flags & GAME_COMMAND_FLAG_APPLY){ + rct_banner* banner = &gBanners[banner_id]; + banner->flags |= BANNER_FLAG_1; + banner->type = 0; + banner->x = x / 32; + banner->y = y / 32; + int eax2 = x, ebx2 = *ebx, ecx2 = y, edx2 = z, esi2 = *esi, edi2 = *edi, ebp2 = *ebp; + RCT2_CALLFUNC_X(0x006B7D86, &eax2, &ebx2, &ecx2, &edx2, &esi2, &edi2, &ebp2); + if((uint8)eax2 != 0xFF){ + banner->colour = eax2; + banner->flags |= BANNER_FLAG_2; + } + } + } + rct_large_scenery_tile* tile = scenery_entry->large_scenery.tiles; + sint16 F43884 = 0xFFFF; + do{ + if(tile->x_offset == (sint16)0xFFFF){ + break; + } + int x2 = tile->x_offset; + int y2 = tile->y_offset; + switch(rotation){ + case 0:{ + }break; + case 1:{ + int temp = x2; + x2 = y2; + y2 = -temp; + }break; + case 2:{ + x2 = -x2; + y2 = -y2; + }break; + case 3:{ + int temp = y2; + y2 = x2; + x2 = -temp; + }break; + } + x2 += x; + y2 += y; + if(x2 >= 0x1FFF || y2 >= 0x1FFF || x2 < 0 || y2 < 0){ + tile++; + continue; + } + rct_map_element* map_element = map_get_surface_element_at(x2 / 32, y2 / 32); + if(map_element != NULL){ + int height = map_element->base_height * 8; + if(map_element->properties.scenerymultiple.type & 0xF){ + height += 16; + if(map_element->properties.scenerymultiple.type & 0x10){ + height += 16; + } + } + if(height > F43884){ + F43884 = height; + } + } + tile++; + }while(1); + if(z != 0){ + F43884 = z; + } + RCT2_GLOBAL(0x009DEA62, sint16) = F43884; + tile = scenery_entry->large_scenery.tiles; + uint8 tile_num = 0; + do{ + if(tile->x_offset == (sint16)0xFFFF){ + break; + } + int x2 = tile->x_offset; + int y2 = tile->y_offset; + switch(rotation){ + case 0:{ + }break; + case 1:{ + int temp = x2; + x2 = y2; + y2 = -temp; + }break; + case 2:{ + x2 = -x2; + y2 = -y2; + }break; + case 3:{ + int temp = y2; + y2 = x2; + x2 = -temp; + }break; + } + int zLow = (tile->z_offset + F43884) / 8; + int zHigh = (tile->var_6 / 8) + zLow; + int bx = tile->var_7 >> 12; + bx <<= rotation; + uint8 bl = bx; + uint8 bh = bl >> 4; + bl &= 0xF; + bl |= bh; + uint8 F43887 = bl; + x2 += x; + y2 += y; + RCT2_GLOBAL(0x00F43892, sint16) = x2; + RCT2_GLOBAL(0x00F43894, sint16) = y2; + RCT2_GLOBAL(0x00F43896, uint32) = (uint32)(ebx - 3); // this is how ebx flags var is passed to 0x006B8D88 + if(map_can_construct_with_clear_at(x2, y2, zLow, zHigh, (void*)0x006B8D88, bl)){ + if(!(RCT2_GLOBAL(0x00F1AD60, uint8) & 4) && !(RCT2_GLOBAL(0x00F1AD60, uint8) & 2)){ + int b = RCT2_GLOBAL(0x00F1AD60, uint8) & 0x3; + if(RCT2_GLOBAL(0x00F64F14, uint8) && !(RCT2_GLOBAL(0x00F64F14, uint8) & b)){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + RCT2_GLOBAL(0x00F64F14, uint8) = b; + if(x2 >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) || y2 >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_OFF_EDGE_OF_MAP; + *ebx = MONEY32_UNDEFINED; + return; + } + if((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || map_is_location_owned(x2, y2, zLow * 8) || gSandboxMode){ + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + if(!(*ebx & 0x40)){ + footpath_remove_litter(x2, y2, zLow * 8); + int bh = (zHigh - zLow) * 8; + RCT2_CALLPROC_X(0x006E588E, x2, bh << 8 | flags, y2, zLow * 8, 0, 0, 0); + } + rct_map_element *new_map_element = map_element_insert(x2 / 32, y2 / 32, zLow, F43887); + map_animation_create(0xB, x2, y2, zLow); + + new_map_element->clearance_height = zHigh; + new_map_element->type = MAP_ELEMENT_TYPE_SCENERY_MULTIPLE | rotation; + int bx = tile_num; + bx <<= 10; + bx |= entry_index; + new_map_element->properties.scenerymultiple.type = bx; + new_map_element->properties.scenerymultiple.colour[0] = color1; + new_map_element->properties.scenerymultiple.colour[1] = color2; + if(banner_id != 0xFF){ + uint8 bh = banner_id; + bh &= 0xC0; + new_map_element->type |= bh; + bh = banner_id; + bh &= 0x38; + bh <<= 2; + new_map_element->properties.scenerymultiple.colour[0] |= bh; + uint8 bl = banner_id; + bl &= 7; + bl <<= 5; + new_map_element->properties.scenerymultiple.colour[1] |= bl; + } + + if(*ebx & 0x40){ + new_map_element->flags |= MAP_ELEMENT_FLAG_GHOST; + } + if(tile_num == 0){ + RCT2_GLOBAL(0x00F64EBC, rct_map_element*) = new_map_element; + } + map_invalidate_tile_full(x2 / 32, y2 / 32); + } + }else{ + *ebx = MONEY32_UNDEFINED; + return; + } + }else{ + *ebx = MONEY32_UNDEFINED; + return; + } + }else{ + *ebx = MONEY32_UNDEFINED; + return; + } + tile++; + tile_num++; + }while(1); + *ebx = (scenery_entry->large_scenery.price * 10) + RCT2_GLOBAL(0x00F4389A, uint32); + if(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + return; + } + }else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + } + *ebx = MONEY32_UNDEFINED; +} + /** * * rct2: 0x006EC6D7 @@ -729,34 +2361,344 @@ void sub_6A6AA7(int x, int y, rct_map_element *mapElement) */ void map_remove_all_rides() { - int x, y; - rct_map_element *mapElement; + map_element_iterator it; - for (y = 0; y < 256; y++) { - for (x = 0; x < 256; x++) { - repeat_tile: - mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + map_element_iterator_begin(&it); + do { + switch (map_element_get_type(it.element)) { + case MAP_ELEMENT_TYPE_PATH: + if (it.element->type & 1) { + it.element->properties.path.type &= ~8; + it.element->properties.path.addition_status = 255; + } + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (it.element->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) + break; - do { - switch (mapElement->type & MAP_ELEMENT_TYPE_MASK) { - case MAP_ELEMENT_TYPE_PATH: - if (mapElement->type & 1) { - mapElement->properties.path.type &= ~8; - mapElement->properties.path.addition_status = 255; - } - break; - case MAP_ELEMENT_TYPE_ENTRANCE: - if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) - break; + // fall-through + case MAP_ELEMENT_TYPE_TRACK: + sub_6A7594(); + sub_6A6AA7(it.x * 32, it.y * 32, it.element); + map_element_remove(it.element); + map_element_iterator_restart_for_tile(&it); + break; + } + } while (map_element_iterator_next(&it)); +} - // fall-through - case MAP_ELEMENT_TYPE_TRACK: - RCT2_CALLPROC_EBPSAFE(0x006A7594); - sub_6A6AA7(x * 32, y * 32, mapElement); - map_element_remove(mapElement); - goto repeat_tile; - } - } while (!((mapElement++)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); +/** + * + * rct2: 0x0068AB1B + */ +void map_invalidate_map_selection_tiles() +{ + rct_xy16 *position; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 1))) + return; + + for (position = gMapSelectionTiles; position->x != -1; position++) + map_invalidate_tile_full(position->x, position->y); +} + +/** + * + * rct2: 0x0068AAE1 + */ +void map_invalidate_selection_rect() +{ + int x, y, x0, y0, x1, y1; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0))) + return; + + x0 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16); + y0 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16); + x1 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16); + y1 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16); + + for (x = x0; x <= x1; x++) + for (y = y0; y <= y1; y++) + map_invalidate_tile_full(x, y); +} + +/** + * + * rct2: 0x0068B111 + */ +void map_reorganise_elements() +{ + RCT2_CALLPROC_EBPSAFE(0x0068B111); +} + +/** + * + * rct2: 0x0068B044 + */ +int sub_68B044() +{ + return (RCT2_CALLPROC_X(0x0068B044, 0, 0, 0, 0, 0, 0, 0) & 0x100) == 0; +} + +/** + * + * rct2: 0x0068B1F6 + */ +rct_map_element *map_element_insert(int x, int y, int z, int flags) +{ + rct_map_element *originalMapElement, *newMapElement, *insertedElement; + + sub_68B044(); + + newMapElement = RCT2_GLOBAL(0x00140E9A4, rct_map_element*); + originalMapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); + + // Set tile index pointer to point to new element block + TILE_MAP_ELEMENT_POINTER(y * 256 + x) = newMapElement; + + // Copy all elements that are below the insert height + while (z >= originalMapElement->base_height) { + // Copy over map element + *newMapElement = *originalMapElement; + originalMapElement->base_height = 255; + originalMapElement++; + newMapElement++; + + if ((newMapElement - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE) { + // No more elements above the insert element + (newMapElement - 1)->flags &= ~MAP_ELEMENT_FLAG_LAST_TILE; + flags |= MAP_ELEMENT_FLAG_LAST_TILE; + break; } } + + // Insert new map element + insertedElement = newMapElement; + newMapElement->base_height = z; + newMapElement->flags = flags; + newMapElement->clearance_height = z; + *((uint32*)&newMapElement->properties) = 0; + newMapElement++; + + // Insert rest of map elements above insert height + if (!(flags & MAP_ELEMENT_FLAG_LAST_TILE)) { + do { + // Copy over map element + *newMapElement = *originalMapElement; + originalMapElement->base_height = 255; + originalMapElement++; + newMapElement++; + } while (!((newMapElement - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); + } + + RCT2_GLOBAL(0x00140E9A4, rct_map_element*) = newMapElement; + return insertedElement; +} + +/** + * + * rct2: 0x0068B932 + */ +int map_can_construct_with_clear_at(int x, int y, int zLow, int zHigh, void *clearFunc, uint8 bl) +{ + return (RCT2_CALLPROC_X(0x0068B932, x, bl, y, (zHigh << 8) | zLow, 0, 0, (int)clearFunc) & 0x100) == 0; +} + +/** + * + * rct2: 0x0068B93A + */ +int map_can_construct_at(int x, int y, int zLow, int zHigh, uint8 bl) +{ + return map_can_construct_with_clear_at(x, y, zLow, zHigh, (void*)0xFFFFFFFF, bl); +} + +/** + * + * rct2: 0x006BA278 + */ +int sub_6BA278(int ebx) +{ + int eax, ecx, edx, esi, edi, ebp; + RCT2_CALLFUNC_X(0x006BA278, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return eax; +} + +/** + * + * rct2: 0x006E5935 + */ +void map_remove_intersecting_walls(int x, int y, int z0, int z1, int direction) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + + if (mapElement->clearance_height <= z0 || mapElement->base_height >= z1) + continue; + + if (direction != (mapElement->type & 3)) + continue; + + map_element_remove_banner_entry(mapElement); + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); + map_element_remove(mapElement); + mapElement--; + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * Updates grass length, scenery age and jumping fountains. + * + * rct2: 0x006646E1 + */ +void map_update_tiles() +{ + int ignoreScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & ignoreScreenFlags) + return; + + // Update 43 more tiles + for (int j = 0; j < 43; j++) { + int x = 0; + int y = 0; + + uint16 interleaved_xy = RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16); + for (int i = 0; i < 8; i++) { + x = (x << 1) | (interleaved_xy & 1); + interleaved_xy >>= 1; + y = (y << 1) | (interleaved_xy & 1); + interleaved_xy >>= 1; + } + + rct_map_element *mapElement = map_get_surface_element_at(x, y); + if (mapElement != NULL) { + map_update_grass_length(x * 32, y * 32, mapElement); + scenery_update_tile(x * 32, y * 32); + } + + RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16)++; + RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16) &= 0xFFFF; + } +} + +/** + * + * rct2: 0x006647A1 + */ +static void map_update_grass_length(int x, int y, rct_map_element *mapElement) +{ + // Check if tile is grass + if ((mapElement->properties.surface.terrain & 0xE0) && !(mapElement->type & 3)) + return; + + int grassLength = mapElement->properties.surface.grass_length & 7; + + // Check if grass is underwater or outside park + int waterHeight = (mapElement->properties.surface.terrain & 0x1F) * 2; + if (waterHeight > mapElement->base_height || !map_is_location_in_park(x, y)) { + if (grassLength != GRASS_LENGTH_CLEAR_0) + map_set_grass_length(x, y, mapElement, GRASS_LENGTH_CLEAR_0); + + return; + } + + // Grass can't grow any further + if (grassLength == GRASS_LENGTH_CLUMPS_2) + return; + + int z0 = mapElement->base_height; + int z1 = mapElement->base_height + 2; + if (mapElement->properties.surface.slope & 0x10) + z1 += 2; + + // Check objects above grass + rct_map_element *mapElementAbove = mapElement; + for (;;) { + if (mapElementAbove->flags & MAP_ELEMENT_FLAG_LAST_TILE) { + // Grow grass + if (mapElement->properties.surface.grass_length < 0xF0) { + mapElement->properties.surface.grass_length += 0x10; + } else { + mapElement->properties.surface.grass_length += 0x10; + mapElement->properties.surface.grass_length ^= 8; + if (mapElement->properties.surface.grass_length & 8) { + // Random growth rate + mapElement->properties.surface.grass_length |= scenario_rand() & 0x70; + } else { + // Increase length + map_set_grass_length(x, y, mapElement, grassLength + 1); + } + } + } else { + mapElementAbove++; + if (map_element_get_type(mapElementAbove) == MAP_ELEMENT_TYPE_FENCE) + continue; + if (z0 >= mapElementAbove->clearance_height) + continue; + if (z1 < mapElementAbove->base_height) + continue; + } + break; + } +} + +static void map_set_grass_length(int x, int y, rct_map_element *mapElement, int length) +{ + int z0, z1; + + mapElement->properties.surface.grass_length = length; + z0 = mapElement->base_height * 8; + z1 = z0 + 16; + gfx_invalidate_viewport_tile(x, y, z0, z1); +} + +void sub_6A7594() +{ + RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; +} + +int map_element_get_banner_index(rct_map_element *mapElement) +{ + rct_scenery_entry* sceneryEntry; + + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenerymultiple.type & 0x3FF]; + if (sceneryEntry->large_scenery.var_11 == 0xFF) + return -1; + + return + (mapElement->type & MAP_ELEMENT_QUADRANT_MASK) | + ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | + ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); + case MAP_ELEMENT_TYPE_FENCE: + sceneryEntry = g_wallSceneryEntries[mapElement->properties.fence.type]; + if (sceneryEntry->wall.var_0D == 0xFF) + return -1; + + return mapElement->properties.fence.item[0]; + case MAP_ELEMENT_TYPE_BANNER: + return mapElement->properties.banner.index; + default: + return -1; + } +} + +void map_element_remove_banner_entry(rct_map_element *mapElement) +{ + int bannerIndex = map_element_get_banner_index(mapElement); + if (bannerIndex == -1) + return; + + rct_banner* banner = &gBanners[bannerIndex]; + if (banner->type != BANNER_NULL) { + window_close_by_number(WC_BANNER, bannerIndex); + banner->type = BANNER_NULL; + user_string_free(banner->string_idx); + } } \ No newline at end of file diff --git a/src/world/map.h b/src/world/map.h index 55e9dbe75a..db3cda5299 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -24,10 +24,10 @@ #include "../common.h" typedef struct { - uint8 slope; //4 - uint8 terrain; //5 - uint8 grass_length; - uint8 ownership; + uint8 slope; //4 0xE0 Edge Style, 0x1F Slope + uint8 terrain; //5 0xE0 Terrain Style, 0x1F Water height + uint8 grass_length; //6 + uint8 ownership; //7 } rct_map_element_surface_properties; typedef struct { @@ -39,16 +39,21 @@ typedef struct { typedef struct { uint8 type; //4 - uint8 sequence; //5 - uint8 colour; //6 + union{ + struct{ + uint8 sequence; //5 + uint8 colour; //6 + }; + uint16 maze_entry; // 5 + }; uint8 ride_index; //7 } rct_map_element_track_properties; typedef struct { uint8 type; //4 uint8 age; //5 - uint8 colour; //6 - uint8 unused; //7 + uint8 colour_1; //6 + uint8 colour_2; //7 } rct_map_element_scenery_properties; typedef struct { @@ -59,13 +64,12 @@ typedef struct { } rct_map_element_entrance_properties; typedef struct { - uint8 slope; //4 + uint8 type; //4 uint8 item[3]; //5 } rct_map_element_fence_properties; typedef struct { - uint8 type; //4 - uint8 index; //5 + uint16 type; //4 uint8 colour[2]; //6 } rct_map_element_scenerymultiple_properties; @@ -125,6 +129,8 @@ enum { }; enum { + MAP_ELEMENT_FLAG_GHOST = (1 << 4), + MAP_ELEMENT_FLAG_BROKEN = (1 << 5), MAP_ELEMENT_FLAG_LAST_TILE = (1 << 7) }; @@ -154,6 +160,23 @@ enum { TERRAIN_EDGE_ICE }; +enum { + GRASS_LENGTH_MOWED, + GRASS_LENGTH_CLEAR_0, + GRASS_LENGTH_CLEAR_1, + GRASS_LENGTH_CLEAR_2, + GRASS_LENGTH_CLUMPS_0, + GRASS_LENGTH_CLUMPS_1, + GRASS_LENGTH_CLUMPS_2 +}; + +enum { + OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED = (1 << 4), + OWNERSHIP_OWNED = (1 << 5), + OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE = (1 << 6), + OWNERSHIP_AVAILABLE = (1 << 7) +}; + enum { PATH_QUEUE, PATH_TARMAC, @@ -163,6 +186,10 @@ enum { PATH_TILE }; +enum { + PATH_FLAG_QUEUE_BANNER = 1 << 3 +}; + enum { ENTRANCE_TYPE_RIDE_ENTRANCE, ENTRANCE_TYPE_RIDE_EXIT, @@ -174,6 +201,9 @@ enum { #define MAP_ELEMENT_DIRECTION_MASK 0x03 #define MAP_ELEMENT_SLOPE_MASK 0x1F +#define MAP_ELEMENT_SLOPE_EDGE_STYLE_MASK 0xE0 + +// Terrain #define MAP_ELEMENT_WATER_HEIGHT_MASK 0x1F #define MAP_ELEMENT_SURFACE_TERRAIN_MASK 0xE0 @@ -182,8 +212,26 @@ enum { #define MAX_MAP_ELEMENTS 196608 #define MAX_TILE_MAP_ELEMENT_POINTERS (256 * 256) +#define MAP_ELEMENT_LARGE_TYPE_MASK 0x3FF + #define TILE_UNDEFINED_MAP_ELEMENT (rct_map_element*)-1 +typedef struct { + uint8 x, y; +} rct_xy8; + +typedef struct { + sint16 x, y; +} rct_xy16; + +typedef struct { + sint16 x, y, z; +} rct_xyz16; + +typedef struct { + int x, y; + rct_map_element *element; +} rct_xy_element; typedef struct { uint16 x; @@ -192,21 +240,34 @@ typedef struct { uint8 direction; } rct2_peep_spawn; +extern const rct_xy16 TileDirectionDelta[]; +extern rct_xy16 *gMapSelectionTiles; +// Used in the land tool window to allow dragging and changing land styles +extern bool LandPaintMode; +// Used in the land rights tool window to either buy land rights or construction rights +extern bool LandRightsMode; +// Used in the clear scenery tool +extern bool gClearSmallScenery; +extern bool gClearLargeScenery; +extern bool gClearFootpath; -void map_init(); +void map_init(int size); void map_update_tile_pointers(); +rct_map_element *map_get_first_element_at(int x, int y); +int map_element_is_last_for_tile(rct_map_element *element); +int map_element_get_type(rct_map_element *element); int map_element_get_terrain(rct_map_element *element); int map_element_get_terrain_edge(rct_map_element *element); void map_element_set_terrain(rct_map_element *element, int terrain); void map_element_set_terrain_edge(rct_map_element *element, int terrain); int map_height_from_slope(int x, int y, int slope); rct_map_element *map_get_surface_element_at(int x, int y); +rct_map_element* map_get_path_element_at(int x, int y, int z); int map_element_height(int x, int y); void sub_68B089(); -int map_coord_is_connected(uint16 coordinate, uint8 height, uint8 face_direction); -void map_invalidate_animations(); +int map_coord_is_connected(int x, int y, int z, uint8 faceDirection); void sub_6A876D(); -int sub_664F72(int x, int y, int z); +int map_is_location_owned(int x, int y, int z); int map_is_location_in_park(int x, int y); void map_invalidate_tile(int x, int y, int zLow, int zHigh); void map_invalidate_tile_full(int x, int y); @@ -214,12 +275,55 @@ int map_get_station(rct_map_element *mapElement); void map_element_remove(rct_map_element *mapElement); void sub_6A6AA7(int x, int y, rct_map_element *mapElement); void map_remove_all_rides(); +void map_invalidate_map_selection_tiles(); +void map_invalidate_selection_rect(); +void map_reorganise_elements(); +int sub_68B044(); +rct_map_element *map_element_insert(int x, int y, int z, int flags); +int map_can_construct_with_clear_at(int x, int y, int zLow, int zHigh, void *clearFunc, uint8 bl); +int map_can_construct_at(int x, int y, int zLow, int zHigh, uint8 bl); +int sub_6BA278(int ebx); +void rotate_map_coordinates(sint16* x, sint16* y, uint8 rotation); +money32 map_clear_scenery(int x0, int y0, int x1, int y1, int flags); +money32 lower_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags); +money32 raise_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags); -void fountain_update_all(); - +void game_command_remove_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_remove_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_scenery_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_fence_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_large_scenery_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_banner_colour(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); void game_command_clear_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_change_surface_style(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_raise_land(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_lower_land(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_raise_water(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_lower_water(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_remove_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); #define GET_MAP_ELEMENT(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS, rct_map_element)[x])) #define TILE_MAP_ELEMENT_POINTER(x) (RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[x]) +typedef struct { + int x; + int y; + rct_map_element *element; +} map_element_iterator; + +void map_element_iterator_begin(map_element_iterator *it); +int map_element_iterator_next(map_element_iterator *it); +void map_element_iterator_restart_for_tile(map_element_iterator *it); + +void map_remove_intersecting_walls(int x, int y, int z0, int z1, int direction); +void map_update_tiles(); + +void sub_6A7594(); +int map_element_get_banner_index(rct_map_element *mapElement); +void map_element_remove_banner_entry(rct_map_element *mapElement); + #endif diff --git a/src/world/map_animation.c b/src/world/map_animation.c new file mode 100644 index 0000000000..3a31fe5d82 --- /dev/null +++ b/src/world/map_animation.c @@ -0,0 +1,545 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#include "../addresses.h" +#include "../ride/ride.h" +#include "../ride/ride_data.h" +#include "../ride/track.h" +#include "map_animation.h" +#include "map.h" +#include "scenery.h" +#include "sprite.h" + +typedef bool (*map_animation_invalidate_event_handler)(int x, int y, int baseZ); + +static bool map_animation_invalidate(rct_map_animation *obj); + +static const map_animation_invalidate_event_handler _animatedObjectEventHandlers[MAP_ANIMATION_TYPE_COUNT]; + +rct_map_animation *gAnimatedObjects = (rct_map_animation*)0x013886A0; + +/** + * + * rct2: 0x0068AF67 + * + * @param type (dh) + * @param x (ax) + * @param y (cx) + * @param z (dl) + */ +void map_animation_create(int type, int x, int y, int z) +{ + rct_map_animation *aobj = &gAnimatedObjects[0]; + int numAnimatedObjects = RCT2_GLOBAL(0x0138B580, uint16); + for (int i = 0; i < numAnimatedObjects; i++, aobj++) { + if (aobj->x != x) + continue; + if (aobj->y != y) + continue; + if (aobj->baseZ != z) + continue; + if (aobj->type != type) + continue; + // Animation already exists + return; + } + + // Create new animation + RCT2_GLOBAL(0x0138B580, uint16)++; + aobj->type = type; + aobj->x = x; + aobj->y = y; + aobj->baseZ = z; +} + +/** + * + * rct2: 0x0068AFAD + */ +void map_animation_invalidate_all() +{ + rct_map_animation *aobj = &gAnimatedObjects[0]; + int numAnimatedObjects = RCT2_GLOBAL(0x0138B580, uint16); + while (numAnimatedObjects > 0) { + if (map_animation_invalidate(aobj)) { + // Remove animated object + RCT2_GLOBAL(0x0138B580, uint16)--; + numAnimatedObjects--; + if (numAnimatedObjects > 0) + memmove(aobj, aobj + 1, numAnimatedObjects * sizeof(rct_map_animation)); + } else { + numAnimatedObjects--; + aobj++; + } + } +} + +/** + * @returns true if the animation should be removed. + */ +static bool map_animation_invalidate(rct_map_animation *obj) +{ + assert(obj->type < MAP_ANIMATION_TYPE_COUNT); + + return _animatedObjectEventHandlers[obj->type](obj->x, obj->y, obj->baseZ); +} + +/** + * + * rct2: 0x00666670 + */ +static bool map_animation_invalidate_ride_entrance(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + rct_ride *ride; + const rct_ride_entrance_definition *entranceDefinition; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_RIDE_ENTRANCE) + continue; + + ride = GET_RIDE(mapElement->properties.entrance.ride_index); + entranceDefinition = &RideEntranceDefinitions[ride->entrance_style]; + + int height = (mapElement->base_height * 8) + entranceDefinition->height + 8; + map_invalidate_tile(x, y, height, height + 16); + return false; + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006A7BD4 + */ +static bool map_animation_invalidate_queue_banner(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + if (!(mapElement->flags & 1)) + continue; + if (!(mapElement->properties.path.type & PATH_FLAG_QUEUE_BANNER)) + continue; + + int direction = ((mapElement->type >> 6) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3; + if (direction == MAP_ELEMENT_DIRECTION_NORTH || direction == MAP_ELEMENT_DIRECTION_EAST) { + baseZ = mapElement->base_height * 8; + map_invalidate_tile(x, y, baseZ + 16, baseZ + 30); + } + return false; + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006E32C9 + */ +static bool map_animation_invalidate_small_scenery(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + rct_sprite *sprite; + rct_peep *peep; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY) + continue; + if (mapElement->flags & (1 << 4)) + continue; + + sceneryEntry = g_smallSceneryEntries[mapElement->properties.scenery.type]; + if (sceneryEntry->small_scenery.flags & 0xD800) { + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + return false; + } + + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_IS_CLOCK) { + // Peep, looking at scenery + if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x3FF)) { + int direction = mapElement->type & 3; + int x2 = x - TileDirectionDelta[direction].x; + int y2 = y - TileDirectionDelta[direction].y; + + uint16 spriteIdx = RCT2_ADDRESS(0x00F1EF60, uint16)[((x2 & 0x1FE0) << 3) | (y2 >> 5)]; + for (; spriteIdx != 0xFFFF; spriteIdx = sprite->unknown.next_in_quadrant) { + sprite = &g_sprite_list[spriteIdx]; + if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_PEEP) + continue; + + peep = &sprite->peep; + if (peep->state != PEEP_STATE_WALKING) + continue; + if (peep->z != mapElement->base_height * 8) + continue; + if (peep->action < PEEP_ACTION_NONE_1) + continue; + + peep->action = PEEP_ACTION_CHECK_TIME; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + sub_693B58(peep); + RCT2_CALLPROC_X(0x006EC53F, 0, 0, 0, 0, (int)peep, 0, 0); + break; + } + } + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + return false; + } + } while (!map_element_is_last_for_tile(mapElement++)); + return true; +} + +/** + * + * rct2: 0x00666C63 + */ +static bool map_animation_invalidate_park_entrance(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + if (mapElement->properties.entrance.index & 0x0F) + continue; + + baseZ = mapElement->base_height * 8; + map_invalidate_tile(x, y, baseZ + 32, baseZ + 64); + return false; + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006CE29E + */ +static bool map_animation_invalidate_track_waterfall(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if (mapElement->properties.track.type == TRACK_ELEM_WATERFALL) { + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, z + 14, z + 46); + return false; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006CE2F3 + */ +static bool map_animation_invalidate_track_rapids(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if (mapElement->properties.track.type == TRACK_ELEM_RAPIDS) { + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, z + 14, z + 18); + return false; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006CE39D + */ +static bool map_animation_invalidate_track_onridephoto(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + bool wasInvalidated = false; + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if (mapElement->properties.track.type == TRACK_ELEM_ON_RIDE_PHOTO) { + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + if (mapElement->properties.track.sequence & 0xF0) { + mapElement->properties.track.sequence -= 0x10; + return false; + } else { + return true; + } + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006CE348 + */ +static bool map_animation_invalidate_track_whirlpool(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if (mapElement->properties.track.type == TRACK_ELEM_WHIRLPOOL) { + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, z + 14, z + 18); + return false; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006CE3FA + */ +static bool map_animation_invalidate_track_spinningtunnel(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if (mapElement->properties.track.type == TRACK_ELEM_SPINNING_TUNNEL) { + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, z + 14, z + 32); + return false; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x0068DF8F + */ +static bool map_animation_invalidate_remove(int x, int y, int baseZ) +{ + return true; +} + +/** + * + * rct2: 0x006BA2BB + */ +static bool map_animation_invalidate_banner(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_BANNER) + continue; + + baseZ = mapElement->base_height * 8; + map_invalidate_tile(x, y, baseZ, baseZ + 16); + return false; + } while (!map_element_is_last_for_tile(mapElement++)); + + return true; +} + +/** + * + * rct2: 0x006B94EB + */ +static bool map_animation_invalidate_large_scenery(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + + bool wasInvalidated = false; + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) + continue; + + sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenery.type & 0x3FF]; + if (sceneryEntry->large_scenery.flags & (1 << 3)) { + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, z, z + 16); + wasInvalidated = true; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return !wasInvalidated; +} + +/** + * + * rct2: 0x006E5B50 + */ +static bool map_animation_invalidate_wall_unknown(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 1) + return false; + + bool wasInvalidated = false; + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + + sceneryEntry = g_wallSceneryEntries[mapElement->properties.scenery.type]; + if (!(sceneryEntry->wall.flags & (1 << 4))) + continue; + + uint8 di = 0; + uint8 bl = mapElement->properties.fence.item[2]; + uint8 bh = bl & 0x78; + if (bh != 0) { + if (bh == 0x78) { + bl &= 0x87; + } else { + di |= 2; + if (bh != 40) { + bh += 8; + if (bh == 104 && !(sceneryEntry->wall.flags & (1 << 5))) + bh = 120; + + di |= 1; + bl &= 135; + bl |= bh; + } + } + } + + mapElement->properties.fence.item[2] = bl; + if (di & 1) { + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, z, z + 32); + } + if (di & 2) + wasInvalidated = true; + } while (!map_element_is_last_for_tile(mapElement++)); + + return !wasInvalidated; +} + +/** + * + * rct2: 0x006E5EE4 + */ +static bool map_animation_invalidate_wall(int x, int y, int baseZ) +{ + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + + bool wasInvalidated = false; + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height != baseZ) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + + sceneryEntry = g_wallSceneryEntries[mapElement->properties.scenery.type]; + if (!(sceneryEntry->wall.flags2 & (1 << 4)) && sceneryEntry->wall.var_0D == 255) + continue; + + int z = mapElement->base_height * 8; + map_invalidate_tile(x, y, z, z + 16); + wasInvalidated = true; + } while (!map_element_is_last_for_tile(mapElement++)); + + return !wasInvalidated; +} + +/** rct2: 0x009819DC */ +static const map_animation_invalidate_event_handler _animatedObjectEventHandlers[MAP_ANIMATION_TYPE_COUNT] = { + map_animation_invalidate_ride_entrance, + map_animation_invalidate_queue_banner, + map_animation_invalidate_small_scenery, + map_animation_invalidate_park_entrance, + map_animation_invalidate_track_waterfall, + map_animation_invalidate_track_rapids, + map_animation_invalidate_track_onridephoto, + map_animation_invalidate_track_whirlpool, + map_animation_invalidate_track_spinningtunnel, + map_animation_invalidate_remove, + map_animation_invalidate_banner, + map_animation_invalidate_large_scenery, + map_animation_invalidate_wall_unknown, + map_animation_invalidate_wall +}; \ No newline at end of file diff --git a/src/world/map_animation.h b/src/world/map_animation.h new file mode 100644 index 0000000000..ce749b6110 --- /dev/null +++ b/src/world/map_animation.h @@ -0,0 +1,60 @@ +/***************************************************************************** + * 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 _MAP_ANIMATION_H_ +#define _MAP_ANIMATION_H_ + +#include "../common.h" + +/** + * Animated object + * size: 0x06 + */ +typedef struct { + uint8 baseZ; + uint8 type; + uint16 x; + uint16 y; +} rct_map_animation; + +enum { + MAP_ANIMATION_TYPE_RIDE_ENTRANCE, + MAP_ANIMATION_TYPE_QUEUE_BANNER, + MAP_ANIMATION_TYPE_SMALL_SCENERY, + MAP_ANIMATION_TYPE_PARK_ENTRANCE, + MAP_ANIMATION_TYPE_TRACK_WATERFALL, + MAP_ANIMATION_TYPE_TRACK_RAPIDS, + MAP_ANIMATION_TYPE_TRACK_ONRIDEPHOTO, + MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, + MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, + MAP_ANIMATION_TYPE_REMOVE, + MAP_ANIMATION_TYPE_BANNER, + MAP_ANIMATION_TYPE_LARGE_SCENERY, + MAP_ANIMATION_TYPE_WALL_UNKNOWN, + MAP_ANIMATION_TYPE_WALL, + MAP_ANIMATION_TYPE_COUNT +}; + +extern rct_map_animation *gAnimatedObjects; + +void map_animation_create(int type, int x, int y, int z); +void map_animation_invalidate_all(); + +#endif \ No newline at end of file diff --git a/src/world/map_helpers.c b/src/world/map_helpers.c new file mode 100644 index 0000000000..be2644ecaf --- /dev/null +++ b/src/world/map_helpers.c @@ -0,0 +1,325 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#include "map.h" +#include "map_helpers.h" + +/** + * Not perfect, this still leaves some particular tiles unsmoothed. + */ +int map_smooth(int l, int t, int r, int b) +{ + int i, x, y, highest, count, cornerHeights[4], doubleCorner, raisedLand = 0; + rct_map_element *mapElement, *mapElement2; + for (y = t; y < b; y++) { + for (x = l; x < r; x++) { + mapElement = map_get_surface_element_at(x, y); + mapElement->properties.surface.slope &= ~0x1F; + + // Raise to edge height - 2 + highest = mapElement->base_height; + highest = max(highest, map_get_surface_element_at(x - 1, y + 0)->base_height); + highest = max(highest, map_get_surface_element_at(x + 1, y + 0)->base_height); + highest = max(highest, map_get_surface_element_at(x + 0, y - 1)->base_height); + highest = max(highest, map_get_surface_element_at(x + 0, y + 1)->base_height); + if (mapElement->base_height < highest - 2) { + raisedLand = 1; + mapElement->base_height = mapElement->clearance_height = highest - 2; + } + + // Check corners + doubleCorner = -1; + cornerHeights[0] = map_get_surface_element_at(x - 1, y - 1)->base_height; + cornerHeights[1] = map_get_surface_element_at(x + 1, y - 1)->base_height; + cornerHeights[2] = map_get_surface_element_at(x + 1, y + 1)->base_height; + cornerHeights[3] = map_get_surface_element_at(x - 1, y + 1)->base_height; + highest = mapElement->base_height; + for (i = 0; i < 4; i++) + highest = max(highest, cornerHeights[i]); + + if (highest >= mapElement->base_height + 4) { + count = 0; + int canCompensate = 1; + for (i = 0; i < 4; i++) + if (cornerHeights[i] == highest){ + count++; + + // Check if surrounding corners aren't too high. The current tile + // can't compensate for all the height differences anymore if it has + // the extra height slope. + int highestOnLowestSide; + switch (i){ + case 0: + highestOnLowestSide = max( + map_get_surface_element_at(x + 1, y)->base_height, + map_get_surface_element_at(x, y + 1)->base_height); + break; + case 1: + highestOnLowestSide = max( + map_get_surface_element_at(x - 1, y)->base_height, + map_get_surface_element_at(x, y + 1)->base_height); + break; + case 2: + highestOnLowestSide = max( + map_get_surface_element_at(x - 1, y)->base_height, + map_get_surface_element_at(x, y - 1)->base_height); + break; + case 3: + highestOnLowestSide = max( + map_get_surface_element_at(x + 1, y)->base_height, + map_get_surface_element_at(x, y - 1)->base_height); + break; + } + + if (highestOnLowestSide > mapElement->base_height){ + mapElement->base_height = mapElement->clearance_height = highestOnLowestSide; + raisedLand = 1; + canCompensate = 0; + } + } + + if (count == 1 && canCompensate) { + if (mapElement->base_height < highest - 4) { + mapElement->base_height = mapElement->clearance_height = highest - 4; + raisedLand = 1; + } + if (cornerHeights[0] == highest && cornerHeights[2] <= cornerHeights[0] - 4) + doubleCorner = 0; + else if (cornerHeights[1] == highest && cornerHeights[3] <= cornerHeights[1] - 4) + doubleCorner = 1; + else if (cornerHeights[2] == highest && cornerHeights[0] <= cornerHeights[2] - 4) + doubleCorner = 2; + else if (cornerHeights[3] == highest && cornerHeights[1] <= cornerHeights[3] - 4) + doubleCorner = 3; + } else { + if (mapElement->base_height < highest - 2) { + mapElement->base_height = mapElement->clearance_height = highest - 2; + raisedLand = 1; + } + } + } + + if (doubleCorner != -1) { + mapElement->properties.surface.slope |= 16; + switch (doubleCorner) { + case 0: + mapElement->properties.surface.slope |= 2 | 4 | 8; + break; + case 1: + mapElement->properties.surface.slope |= 1 | 2 | 4; + break; + case 2: + mapElement->properties.surface.slope |= 1 | 2 | 8; + break; + case 3: + mapElement->properties.surface.slope |= 1 | 4 | 8; + break; + } + } else { + // Corners + mapElement2 = map_get_surface_element_at(x + 1, y + 1); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 1; + + mapElement2 = map_get_surface_element_at(x - 1, y + 1); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 8; + + mapElement2 = map_get_surface_element_at(x + 1, y - 1); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 2; + + mapElement2 = map_get_surface_element_at(x - 1, y - 1); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 4; + + // Sides + mapElement2 = map_get_surface_element_at(x + 1, y + 0); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 1 | 2; + + mapElement2 = map_get_surface_element_at(x - 1, y + 0); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 4 | 8; + + mapElement2 = map_get_surface_element_at(x + 0, y - 1); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 2 | 4; + + mapElement2 = map_get_surface_element_at(x + 0, y + 1); + if (mapElement2->base_height > mapElement->base_height) + mapElement->properties.surface.slope |= 1 | 8; + + // Raise + if (mapElement->properties.surface.slope == (1 | 2 | 4 | 8)) { + mapElement->properties.surface.slope &= ~0x1F; + mapElement->base_height = mapElement->clearance_height += 2; + } + } + } + } + + return raisedLand; +} + +int map_get_corner_height(int x, int y, int corner) +{ + rct_map_element *mapElement = map_get_surface_element_at(x, y); + int baseHeight = mapElement->base_height; + int slope = mapElement->properties.surface.slope; + int doubleCorner = slope & 16; + if (doubleCorner) { + if (!(slope & 1)) doubleCorner = 4; + else if (!(slope & 2)) doubleCorner = 8; + else if (!(slope & 4)) doubleCorner = 1; + else if (!(slope & 8)) doubleCorner = 2; + } + + switch (corner) { + case 0: + return baseHeight + (slope & 1 ? (doubleCorner == 1 ? 4 : 2) : 0); + case 1: + return baseHeight + (slope & 8 ? (doubleCorner == 8 ? 4 : 2) : 0); + case 2: + return baseHeight + (slope & 2 ? (doubleCorner == 2 ? 4 : 2) : 0); + case 3: + return baseHeight + (slope & 4 ? (doubleCorner == 4 ? 4 : 2) : 0); + default: + return baseHeight; + } +} + +/** + * There are non-smoothed tiles with this version, but diagonal land blocks end up being wavy. + */ +int map_smooth_wavy(int l, int t, int r, int b) +{ + int i, x, y, highest, count, cornerHeights[4], doubleCorner, raisedLand = 0; + rct_map_element *mapElement; + for (y = t; y < b; y++) { + for (x = l; x < r; x++) { + mapElement = map_get_surface_element_at(x, y); + mapElement->properties.surface.slope &= ~0x1F; + + // Raise to edge height - 2 + highest = mapElement->base_height; + highest = max(highest, map_get_surface_element_at(x - 1, y + 0)->base_height); + highest = max(highest, map_get_surface_element_at(x + 1, y + 0)->base_height); + highest = max(highest, map_get_surface_element_at(x + 0, y - 1)->base_height); + highest = max(highest, map_get_surface_element_at(x + 0, y + 1)->base_height); + if (mapElement->base_height < highest - 2) { + raisedLand = 1; + mapElement->base_height = mapElement->clearance_height = highest - 2; + } + + // Check corners + doubleCorner = -1; + cornerHeights[0] = max(map_get_corner_height(x - 1, y - 1, 0), max(map_get_corner_height(x + 1, y + 0, 1), map_get_corner_height(x + 0, y + 1, 2))); + cornerHeights[1] = max(map_get_corner_height(x + 1, y - 1, 1), max(map_get_corner_height(x - 1, y + 0, 0), map_get_corner_height(x + 0, y + 1, 3))); + cornerHeights[2] = max(map_get_corner_height(x + 1, y + 1, 3), max(map_get_corner_height(x + 1, y + 0, 3), map_get_corner_height(x + 0, y - 1, 0))); + cornerHeights[3] = max(map_get_corner_height(x - 1, y + 1, 2), max(map_get_corner_height(x - 1, y + 0, 2), map_get_corner_height(x + 0, y - 1, 1))); + highest = mapElement->base_height; + for (i = 0; i < 4; i++) + highest = max(highest, cornerHeights[i]); + + if (highest >= mapElement->base_height + 4) { + count = 0; + for (i = 0; i < 4; i++) + if (cornerHeights[i] == highest) + count++; + + if (count == 1) { + if (mapElement->base_height < highest - 4) { + mapElement->base_height = mapElement->clearance_height = highest - 4; + raisedLand = 1; + } + if (cornerHeights[0] == highest && cornerHeights[2] <= cornerHeights[0] - 4) + doubleCorner = 0; + else if (cornerHeights[1] == highest && cornerHeights[3] <= cornerHeights[1] - 4) + doubleCorner = 1; + else if (cornerHeights[2] == highest && cornerHeights[0] <= cornerHeights[2] - 4) + doubleCorner = 2; + else if (cornerHeights[3] == highest && cornerHeights[1] <= cornerHeights[3] - 4) + doubleCorner = 3; + } else { + if (mapElement->base_height < highest - 2) { + mapElement->base_height = mapElement->clearance_height = highest - 2; + raisedLand = 1; + } + } + } + + if (doubleCorner != -1) { + mapElement->properties.surface.slope |= 16; + switch (doubleCorner) { + case 0: + mapElement->properties.surface.slope |= 2 | 4 | 8; + break; + case 1: + mapElement->properties.surface.slope |= 1 | 2 | 4; + break; + case 2: + mapElement->properties.surface.slope |= 1 | 2 | 8; + break; + case 3: + mapElement->properties.surface.slope |= 1 | 4 | 8; + break; + } + } else { + // Corners + if ( + map_get_corner_height(x + 1, y + 1, 3) > mapElement->base_height || + map_get_corner_height(x + 1, y + 0, 1) > mapElement->base_height || + map_get_corner_height(x + 0, y + 1, 2) > mapElement->base_height + ) + mapElement->properties.surface.slope |= 1; + + if ( + map_get_corner_height(x - 1, y + 1, 2) > mapElement->base_height || + map_get_corner_height(x - 1, y + 0, 0) > mapElement->base_height || + map_get_corner_height(x + 0, y + 1, 3) > mapElement->base_height + ) + mapElement->properties.surface.slope |= 8; + + if ( + map_get_corner_height(x + 1, y - 1, 1) > mapElement->base_height || + map_get_corner_height(x + 1, y + 0, 3) > mapElement->base_height || + map_get_corner_height(x + 0, y - 1, 0) > mapElement->base_height + ) + mapElement->properties.surface.slope |= 2; + + if ( + map_get_corner_height(x - 1, y - 1, 0) > mapElement->base_height || + map_get_corner_height(x - 1, y + 0, 2) > mapElement->base_height || + map_get_corner_height(x + 0, y - 1, 1) > mapElement->base_height + ) + mapElement->properties.surface.slope |= 4; + + // Raise + if (mapElement->properties.surface.slope == (1 | 2 | 4 | 8)) { + mapElement->properties.surface.slope &= ~0x1F; + mapElement->base_height = mapElement->clearance_height += 2; + } + } + } + } + + return raisedLand; +} \ No newline at end of file diff --git a/src/world/map_helpers.h b/src/world/map_helpers.h new file mode 100644 index 0000000000..423bb4c25e --- /dev/null +++ b/src/world/map_helpers.h @@ -0,0 +1,26 @@ +/***************************************************************************** + * 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 _MAP_HELPERS_H_ +#define _MAP_HELPERS_H_ + +int map_smooth(int l, int t, int r, int b); + +#endif \ No newline at end of file diff --git a/src/world/mapgen.c b/src/world/mapgen.c new file mode 100644 index 0000000000..b71fd3c6ca --- /dev/null +++ b/src/world/mapgen.c @@ -0,0 +1,779 @@ +/***************************************************************************** + * 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 _USE_MATH_DEFINES + #define _USE_MATH_DEFINES +#endif +#include +#include +#include "../addresses.h" +#include "../object.h" +#include "map.h" +#include "map_helpers.h" +#include "mapgen.h" +#include "scenery.h" + +#pragma region Random objects + +const char *GrassTrees[] = { + // Dark + "TCF ", // Caucasian Fir Tree + "TRF ", // Red Fir Tree + "TRF2 ", // Red Fir Tree + "TSP ", // Scots Pine Tree + "TMZP ", // Montezuma Pine Tree + "TAP ", // Aleppo Pine Tree + "TCRP ", // Corsican Pine Tree + "TBP ", // Black Poplar Tree + + // Light + "TCL ", // Cedar of Lebanon Tree + "TEL ", // European Larch Tree +}; + +// Trees to be placed in proximity to water +const char *GrassWaterTrees[] = { + "TWW " // Weeping Willow Tree +}; + +const char *DesertTrees[] = { + "TMP ", // Monkey-Puzzle Tree + "THL ", // Honey Locust Tree + "TH1 ", // Canary Palm Tree + "TH2 ", // Palm Tree + "TPM ", // Palm Tree + "TROPT1 ", // Tree + "TBC ", // Cactus + "TSC ", // Cactus +}; + +const char *SnowTrees[] = { + "TCFS ", // Snow-covered Caucasian Fir Tree + "TNSS ", // Snow-covered Norway Spruce Tree + "TRF3 ", // Snow-covered Red Fir Tree + "TRFS ", // Snow-covered Red Fir Tree +}; + +#pragma endregion + +// Randomly chosen base terrains. We rarely want a whole map made out of chequerboard or rock. +const uint8 BaseTerrain[] = { TERRAIN_GRASS, TERRAIN_SAND, TERRAIN_SAND_LIGHT, TERRAIN_DIRT, TERRAIN_ICE }; + +#define BLOB_HEIGHT 255 + +static void mapgen_place_trees(); +static void mapgen_set_water_level(int height); +static void mapgen_blobs(int count, int lowSize, int highSize, int lowHeight, int highHeight); +static void mapgen_blob(int cx, int cy, int size, int height); +static void mapgen_smooth_height(int iterations); +static void mapgen_set_height(); + +static void mapgen_simplex(); + +static int _heightSize; +static uint8 *_height; + +static int get_height(int x, int y) +{ + if (x >= 0 && y >= 0 && x < _heightSize && y < _heightSize) + return _height[x + y * _heightSize]; + else + return 0; +} + +static void set_height(int x, int y, int height) +{ + if (x >= 0 && y >= 0 && x < _heightSize && y < _heightSize) + _height[x + y * _heightSize] = height; +} + +void mapgen_generate_blank(mapgen_settings *settings) +{ + int x, y; + rct_map_element *mapElement; + + map_init(settings->mapSize); + for (y = 1; y < settings->mapSize - 1; y++) { + for (x = 1; x < settings->mapSize - 1; x++) { + mapElement = map_get_surface_element_at(x, y); + map_element_set_terrain(mapElement, settings->floor); + map_element_set_terrain_edge(mapElement, settings->wall); + mapElement->base_height = settings->height; + mapElement->clearance_height = settings->height; + } + } + + mapgen_set_water_level(settings->waterLevel); +} + +void mapgen_generate(mapgen_settings *settings) +{ + int x, y, mapSize, floorTexture, wallTexture, waterLevel; + rct_map_element *mapElement; + + srand((unsigned int)time(NULL)); + + mapSize = settings->mapSize; + floorTexture = settings->floor; + wallTexture = settings->wall; + waterLevel = settings->waterLevel; + + if (floorTexture == -1) + floorTexture = BaseTerrain[rand() % countof(BaseTerrain)]; + + if (wallTexture == -1) { + // Base edge type on surface type + switch (floorTexture) { + case TERRAIN_DIRT: + wallTexture = TERRAIN_EDGE_WOOD_RED; + break; + case TERRAIN_ICE: + wallTexture = TERRAIN_EDGE_ICE; + break; + default: + wallTexture = TERRAIN_EDGE_ROCK; + break; + } + } + + // Initialise the base map + map_init(mapSize); + for (y = 1; y < mapSize - 1; y++) { + for (x = 1; x < mapSize - 1; x++) { + mapElement = map_get_surface_element_at(x, y); + map_element_set_terrain(mapElement, floorTexture); + map_element_set_terrain_edge(mapElement, wallTexture); + mapElement->base_height = settings->height; + mapElement->clearance_height = settings->height; + } + } + + // Create the temporary height map and initialise + _heightSize = mapSize * 2; + _height = (uint8*)malloc(_heightSize * _heightSize * sizeof(uint8)); + memset(_height, 0, _heightSize * _heightSize * sizeof(uint8)); + + if (1) { + mapgen_simplex(settings); + mapgen_smooth_height(2 + (rand() % 6)); + } else { + // Keep overwriting the map with rough cicular blobs of different sizes and heights. + // This procedural method can produce intersecting contour like land and lakes. + // Large blobs, general shape of map + mapgen_blobs(6, _heightSize / 2, _heightSize * 4, 4, 16); + // Medium blobs + mapgen_blobs(12, _heightSize / 16, _heightSize / 8, 4, 18); + // Small blobs, small hills and lakes + mapgen_blobs(32, _heightSize / 32, _heightSize / 16, 4, 18); + + // Smooth the land so that their aren't cliffs round every blob. + mapgen_smooth_height(2); + } + + // Set the game map to the height map + mapgen_set_height(); + free(_height); + + // Set the tile slopes so that there are no cliffs + while (map_smooth(1, 1, mapSize - 1, mapSize - 1)) { } + + // Add the water + mapgen_set_water_level(waterLevel); + + // Add sandy beaches + int beachTexture = floorTexture; + if (settings->floor == -1 && floorTexture == TERRAIN_GRASS) { + switch (rand() % 4) { + case 0: + beachTexture = TERRAIN_SAND; + break; + case 1: + beachTexture = TERRAIN_SAND_LIGHT; + break; + } + } + for (y = 1; y < mapSize - 1; y++) { + for (x = 1; x < mapSize - 1; x++) { + mapElement = map_get_surface_element_at(x, y); + + if (mapElement->base_height < waterLevel + 6) + map_element_set_terrain(mapElement, beachTexture); + } + } + + // Place the trees + if (settings->trees != 0) + mapgen_place_trees(); + + map_reorganise_elements(); +} + +static void mapgen_place_tree(int type, int x, int y) +{ + int surfaceZ; + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry = g_smallSceneryEntries[type]; + + surfaceZ = map_element_height(x * 32 + 16, y * 32 + 16) / 8; + mapElement = map_element_insert(x, y, surfaceZ, (1 | 2 | 4 | 8)); + mapElement->clearance_height = surfaceZ + (sceneryEntry->small_scenery.height >> 3); + + mapElement->type = MAP_ELEMENT_TYPE_SCENERY | (rand() % 3); + mapElement->properties.scenery.type = type; + mapElement->properties.scenery.age = 0; + mapElement->properties.scenery.colour_1 = 26; + mapElement->properties.scenery.colour_1 = 18; +} + +/** + * Randomly places a selection of preset trees on the map. Picks the right tree for the terrain it is placing it on. + */ +static void mapgen_place_trees() +{ + int x, y, mapSize, i, j, rindex, type; + rct_map_element *mapElement; + + int numGrassTreeIds = 0, numDesertTreeIds = 0, numSnowTreeIds = 0; + int *grassTreeIds = (int*)malloc(countof(GrassTrees) * sizeof(int)); + int *desertTreeIds = (int*)malloc(countof(DesertTrees) * sizeof(int)); + int *snowTreeIds = (int*)malloc(countof(SnowTrees) * sizeof(int)); + + for (i = 0; i < object_entry_group_counts[OBJECT_TYPE_SMALL_SCENERY]; i++) { + rct_scenery_entry *sceneryEntry = g_smallSceneryEntries[i]; + rct_object_entry_extended *entry = &object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].entries[i]; + + if (sceneryEntry == (rct_scenery_entry*)0xFFFFFFFF || sceneryEntry == NULL) + continue; + + for (j = 0; j < countof(GrassTrees); j++) + if (strncmp(GrassTrees[j], entry->name, 8) == 0) + break; + if (j != countof(GrassTrees)) { + grassTreeIds[numGrassTreeIds++] = i; + continue; + } + + for (j = 0; j < countof(DesertTrees); j++) + if (strncmp(DesertTrees[j], entry->name, 8) == 0) + break; + if (j != countof(DesertTrees)) { + desertTreeIds[numDesertTreeIds++] = i; + continue; + } + + for (j = 0; j < countof(SnowTrees); j++) + if (strncmp(SnowTrees[j], entry->name, 8) == 0) + break; + if (j != countof(SnowTrees)) { + snowTreeIds[numSnowTreeIds++] = i; + continue; + } + } + + mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16); + + int availablePositionsCount = 0; + struct { int x; int y; } tmp, *pos, *availablePositions; + availablePositions = malloc(256 * 256 * sizeof(tmp)); + + // Create list of available tiles + for (y = 1; y < mapSize - 1; y++) { + for (x = 1; x < mapSize - 1; x++) { + mapElement = map_get_surface_element_at(x, y); + + // Exclude water tiles + if ((mapElement->properties.surface.terrain & 0x1F) != 0) + continue; + + pos = &availablePositions[availablePositionsCount++]; + pos->x = x; + pos->y = y; + } + } + + // Shuffle list + for (i = 0; i < availablePositionsCount; i++) { + rindex = rand() % availablePositionsCount; + if (rindex == i) + continue; + + tmp = availablePositions[i]; + availablePositions[i] = availablePositions[rindex]; + availablePositions[rindex] = tmp; + } + + // Place trees + float treeToLandRatio = (10 + (rand() % 30)) / 100.0f; + int numTrees = max(4, (int)(availablePositionsCount * treeToLandRatio)); + + mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16); + for (i = 0; i < numTrees; i++) { + pos = &availablePositions[i]; + + type = -1; + mapElement = map_get_surface_element_at(pos->x, pos->y); + switch (map_element_get_terrain(mapElement)) { + case TERRAIN_GRASS: + case TERRAIN_DIRT: + case TERRAIN_GRASS_CLUMPS: + if (numGrassTreeIds == 0) + break; + + type = grassTreeIds[rand() % numGrassTreeIds]; + break; + + case TERRAIN_SAND: + case TERRAIN_SAND_DARK: + case TERRAIN_SAND_LIGHT: + if (numDesertTreeIds == 0) + break; + + if (rand() % 4 == 0) + type = desertTreeIds[rand() % numDesertTreeIds]; + break; + + case TERRAIN_ICE: + if (numSnowTreeIds == 0) + break; + + type = snowTreeIds[rand() % numSnowTreeIds]; + break; + } + + if (type != -1) + mapgen_place_tree(type, pos->x, pos->y); + } + + free(availablePositions); + free(grassTreeIds); + free(desertTreeIds); + free(snowTreeIds); +} + +/** + * Sets each tile's water level to the specified water level if underneath that water level. + */ +static void mapgen_set_water_level(int waterLevel) +{ + int x, y, mapSize; + rct_map_element *mapElement; + + mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16); + + for (y = 1; y < mapSize - 1; y++) { + for (x = 1; x < mapSize - 1; x++) { + mapElement = map_get_surface_element_at(x, y); + if (mapElement->base_height < waterLevel) + mapElement->properties.surface.terrain |= (waterLevel / 2); + } + } +} + +static void mapgen_blobs(int count, int lowSize, int highSize, int lowHeight, int highHeight) +{ + int i; + int sizeRange = highSize - lowSize; + int heightRange = highHeight - lowHeight; + + int border = 2 + (rand() % 24); + int borderRange = _heightSize - (border * 2); + for (i = 0; i < count; i++) { + int radius = lowSize + (rand() % sizeRange); + mapgen_blob( + border + (rand() % borderRange), + border + (rand() % borderRange), + (int)(M_PI * radius * radius), + lowHeight + (rand() % heightRange) + ); + } +} + +/** + * Sets any holes within a new created blob to the specified height. + */ +static void mapgen_blob_fill(int height) +{ + // For each square find out whether it is landlocked by BLOB_HEIGHT and then fill it if it is + int left = 0, + top = 0, + right = _heightSize - 1, + bottom = _heightSize - 1; + + uint8 *landX = (uint8*)malloc(_heightSize * _heightSize * sizeof(uint8)); + int firstLand, lastLand; + + // Check each row and see if each tile is between first land x and last land x + for (int y = top; y <= bottom; y++) { + // Calculate first land + firstLand = -1; + for (int xx = left; xx <= right; xx++) { + if (get_height(xx, y) == BLOB_HEIGHT) { + firstLand = xx; + break; + } + } + + lastLand = -1; + if (firstLand >= 0) { + // Calculate last land + for (int xx = right; xx >= left; xx--) { + if (get_height(xx, y) == BLOB_HEIGHT) { + lastLand = xx; + break; + } + } + } else { + // No land on this row + continue; + } + + for (int x = left; x <= right; x++) + if (x >= firstLand && x <= lastLand) + landX[x * _heightSize + y] = 1; + } + + // Do the same for Y + for (int x = left; x <= right; x++) { + // Calculate first land + firstLand = -1; + for (int yy = top; yy <= bottom; yy++) { + if (get_height(x, yy) == BLOB_HEIGHT) { + firstLand = yy; + break; + } + } + + lastLand = -1; + if (firstLand >= 0) { + // Calculate last land + for (int yy = bottom; yy >= top; yy--) { + if (get_height(x, yy) == BLOB_HEIGHT) { + lastLand = yy; + break; + } + } + } else { + // No land on this row + continue; + } + + for (int y = top; y <= bottom; y++) { + if (y >= firstLand && y <= lastLand && landX[x * _heightSize + y]) { + // Not only do we know its landlocked to both x and y + // we can change the land too + set_height(x, y, BLOB_HEIGHT); + } + } + } + + // Replace all the BLOB_HEIGHT with the actual land height + for (int x = left; x <= right; x++) + for (int y = top; y <= bottom; y++) + if (get_height(x, y) == BLOB_HEIGHT) + set_height(x, y, height); + + free(landX); +} + +/** + * Sets a rough circular blob of tiles of the specified size to the specified height. + */ +static void mapgen_blob(int cx, int cy, int size, int height) +{ + int x, y, currentSize, direction; + + x = cx; + y = cy; + currentSize = 1; + direction = 0; + set_height(x, y, BLOB_HEIGHT); + + while (currentSize < size) { + if (rand() % 2 == 0) { + set_height(x, y, BLOB_HEIGHT); + currentSize++; + } + + switch (direction) { + case 0: + if (y == 0) { + currentSize = size; + break; + } + + y--; + if (get_height(x + 1, y) != BLOB_HEIGHT) + direction = 1; + else if (get_height(x, y - 1) != BLOB_HEIGHT) + direction = 0; + else if (get_height(x - 1, y) != BLOB_HEIGHT) + direction = 3; + break; + case 1: + if (x == _heightSize - 1) { + currentSize = size; + break; + } + + x++; + if (get_height(x, y + 1) != BLOB_HEIGHT) + direction = 2; + else if (get_height(x + 1, y) != BLOB_HEIGHT) + direction = 1; + else if (get_height(x, y - 1) != BLOB_HEIGHT) + direction = 0; + break; + case 2: + if (y == _heightSize - 1) { + currentSize = size; + break; + } + + y++; + if (get_height(x - 1, y) != BLOB_HEIGHT) + direction = 3; + else if (get_height(x, y + 1) != BLOB_HEIGHT) + direction = 2; + else if (get_height(x + 1, y) != BLOB_HEIGHT) + direction = 1; + break; + case 3: + if (x == 0) { + currentSize = size; + break; + } + + x--; + if (get_height(x, y - 1) != BLOB_HEIGHT) + direction = 0; + else if (get_height(x - 1, y) != BLOB_HEIGHT) + direction = 3; + else if (get_height(x, y + 1) != BLOB_HEIGHT) + direction = 2; + break; + } + } + + mapgen_blob_fill(height); +} + +/** + * Smooths the height map. + */ +static void mapgen_smooth_height(int iterations) +{ + int i, x, y, xx, yy, avg; + int arraySize = _heightSize * _heightSize * sizeof(uint8); + uint8 *copyHeight = malloc(arraySize); + + for (i = 0; i < iterations; i++) { + memcpy(copyHeight, _height, arraySize); + for (y = 1; y < _heightSize - 1; y++) { + for (x = 1; x < _heightSize - 1; x++) { + avg = 0; + for (yy = -1; yy <= 1; yy++) + for (xx = -1; xx <= 1; xx++) + avg += copyHeight[(y + yy) * _heightSize + (x + xx)]; + avg /= 9; + set_height(x, y, avg); + } + } + } + + free(copyHeight); +} + +/** + * Sets the height of the actual game map tiles to the height map. + */ +static void mapgen_set_height() +{ + int x, y, heightX, heightY, mapSize; + rct_map_element *mapElement; + + mapSize = _heightSize / 2; + for (y = 1; y < mapSize - 1; y++) { + for (x = 1; x < mapSize - 1; x++) { + heightX = x * 2; + heightY = y * 2; + + uint8 q00 = get_height(heightX + 0, heightY + 0); + uint8 q01 = get_height(heightX + 0, heightY + 1); + uint8 q10 = get_height(heightX + 1, heightY + 0); + uint8 q11 = get_height(heightX + 1, heightY + 1); + + uint8 baseHeight = (q00 + q01 + q10 + q11) / 4; + + mapElement = map_get_surface_element_at(x, y); + mapElement->base_height = max(2, baseHeight * 2); + mapElement->clearance_height = mapElement->base_height; + + if (q00 > baseHeight) + mapElement->properties.surface.slope |= 4; + if (q01 > baseHeight) + mapElement->properties.surface.slope |= 8; + if (q10 > baseHeight) + mapElement->properties.surface.slope |= 2; + if (q11 > baseHeight) + mapElement->properties.surface.slope |= 1; + } + } +} + +#pragma region Noise + +/** + * Simplex Noise Algorithm with Fractional Brownian Motion + * Based on: + * - https://code.google.com/p/simplexnoise/ + * - https://code.google.com/p/fractalterraingeneration/wiki/Fractional_Brownian_Motion + */ + +static float generate(float x, float y); +static int fast_floor(float x); +static float grad(int hash, float x, float y); + +static uint8 perm[512]; + +static void noise_rand() +{ + for (int i = 0; i < countof(perm); i++) + perm[i] = rand() & 0xFF; +} + +static float fractal_noise(int x, int y, float frequency, int octaves, float lacunarity, float persistence) +{ + float total = 0.0f; + float amplitude = persistence; + for (int i = 0; i < octaves; i++) { + total += generate(x * frequency, y * frequency) * amplitude; + frequency *= lacunarity; + amplitude *= persistence; + } + return total; +} + +static float generate(float x, float y) +{ + const float F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0) + const float G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0 + + float n0, n1, n2; // Noise contributions from the three corners + + // Skew the input space to determine which simplex cell we're in + float s = (x + y) * F2; // Hairy factor for 2D + float xs = x + s; + float ys = y + s; + int i = fast_floor(xs); + int j = fast_floor(ys); + + float t = (float)(i + j) * G2; + float X0 = i - t; // Unskew the cell origin back to (x,y) space + float Y0 = j - t; + float x0 = x - X0; // The x,y distances from the cell origin + float y0 = y - Y0; + + // For the 2D case, the simplex shape is an equilateral triangle. + // Determine which simplex we are in. + int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords + if (x0 > y0) { i1 = 1; j1 = 0; } // lower triangle, XY order: (0,0)->(1,0)->(1,1) + else { i1 = 0; j1 = 1; } // upper triangle, YX order: (0,0)->(0,1)->(1,1) + + // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + // c = (3-sqrt(3))/6 + + float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + float y1 = y0 - j1 + G2; + float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords + float y2 = y0 - 1.0f + 2.0f * G2; + + // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds + int ii = i % 256; + int jj = j % 256; + + // Calculate the contribution from the three corners + float t0 = 0.5f - x0 * x0 - y0 * y0; + if (t0 < 0.0f) n0 = 0.0f; + else { + t0 *= t0; + n0 = t0 * t0 * grad(perm[ii + perm[jj]], x0, y0); + } + + float t1 = 0.5f - x1 * x1 - y1 * y1; + if (t1 < 0.0f) n1 = 0.0f; + else { + t1 *= t1; + n1 = t1 * t1 * grad(perm[ii + i1 + perm[jj + j1]], x1, y1); + } + + float t2 = 0.5f - x2 * x2 - y2 * y2; + if (t2 < 0.0f) n2 = 0.0f; + else { + t2 *= t2; + n2 = t2 * t2 * grad(perm[ii + 1 + perm[jj + 1]], x2, y2); + } + + // Add contributions from each corner to get the final noise value. + // The result is scaled to return values in the interval [-1,1]. + return 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary! +} + +static int fast_floor(float x) +{ + return (x > 0) ? ((int)x) : (((int)x) - 1); +} + +static int mod(int x, int m) +{ + int a = x % m; + return a < 0 ? a + m : a; +} + +static float grad(int hash, float x, float y) +{ + int h = hash & 7; // Convert low 3 bits of hash code + float u = h < 4 ? x : y; // into 8 simple gradient directions, + float v = h < 4 ? y : x; // and compute the dot product with (x,y). + return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -2.0f * v : 2.0f * v); +} + +static void mapgen_simplex(mapgen_settings *settings) +{ + int x, y; + + float freq = settings->simplex_base_freq * (1.0f / _heightSize); + int octaves = settings->simplex_octaves; + + int low = settings->simplex_low; + int high = settings->simplex_high; + + noise_rand(); + for (y = 0; y < _heightSize; y++) { + for (x = 0; x < _heightSize; x++) { + float noiseValue = clamp(-1.0f, fractal_noise(x, y, freq, octaves, 2.0f, 0.65f), 1.0f); + float normalisedNoiseValue = (noiseValue + 1.0f) / 2.0f; + + set_height(x, y, low + (int)(normalisedNoiseValue * high)); + } + } +} + +#pragma endregion \ No newline at end of file diff --git a/src/world/mapgen.h b/src/world/mapgen.h new file mode 100644 index 0000000000..ed6fd47450 --- /dev/null +++ b/src/world/mapgen.h @@ -0,0 +1,46 @@ +/***************************************************************************** + * 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 _MAPGEN_H_ +#define _MAPGEN_H_ + +typedef struct { + // Base + int mapSize; + int height; + int waterLevel; + int floor; + int wall; + + // Features (e.g. tree, rivers, lakes etc.) + int trees; + + // Simplex Noise Parameters + int simplex_low; + int simplex_high; + float simplex_base_freq; + int simplex_octaves; +} mapgen_settings; + +void mapgen_generate_blank(mapgen_settings *settings); +void mapgen_generate(mapgen_settings *settings); +void mapgen_generate_custom_simplex(mapgen_settings *settings); + +#endif \ No newline at end of file diff --git a/src/world/park.c b/src/world/park.c index 7115b5b88d..abb2dd8c19 100644 --- a/src/world/park.c +++ b/src/world/park.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../game.h" #include "../interface/window.h" #include "../localisation/localisation.h" #include "../management/award.h" @@ -32,6 +33,7 @@ #include "../world/map.h" #include "park.h" #include "sprite.h" +#include "../config.h" /** * In a difficult guest generation scenario, no guests will be generated if over this value. @@ -60,7 +62,7 @@ void park_init() int i; RCT2_GLOBAL(0x013CA740, uint8) = 0; - RCT2_GLOBAL(0x013573D4, uint16) = 777; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, uint16) = 777; RCT2_GLOBAL(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8) = 28; RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) = 28; RCT2_GLOBAL(RCT2_ADDRESS_SECURITY_COLOUR, uint8) = 28; @@ -74,7 +76,7 @@ void park_init() RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32) = -1; for (i = 0; i < 20; i++) - RCT2_ADDRESS(0x01358102, uint8)[i] = 0; + gMarketingCampaignDaysLeft[i] = 0; research_reset_items(); finance_init(); @@ -130,24 +132,21 @@ void park_reset_history() */ int park_calculate_size() { - int tiles, x, y; - rct_map_element *mapElement; + int tiles; + map_element_iterator it; tiles = 0; - for (y = 0; y < 256; y++) { - for (x = 0; x < 256; x++) { - mapElement = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[y * 256 + x]; - while (mapElement->type & MAP_ELEMENT_TYPE_MASK) { - mapElement++; - } - - if (mapElement->properties.surface.ownership & 0x30) + map_element_iterator_begin(&it); + do { + if (map_element_get_type(it.element) == MAP_ELEMENT_TYPE_SURFACE) { + if (it.element->properties.surface.ownership & (OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED | OWNERSHIP_OWNED)) { tiles++; + } } - } + } while (map_element_iterator_next(&it)); - if (tiles != RCT2_GLOBAL(RCT2_ADDRESS_PARK_SIZE, sint16)) { - RCT2_GLOBAL(RCT2_ADDRESS_PARK_SIZE, sint16) = tiles; + if (tiles != RCT2_GLOBAL(RCT2_ADDRESS_PARK_SIZE, uint16)) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_SIZE, uint16) = tiles; window_invalidate_by_class(WC_PARK_INFORMATION); } @@ -205,15 +204,13 @@ int calculate_park_rating() // Rides { int i; - short _ax, total_ride_intensity = 0, total_ride_excitement = 0, average_intensity, average_excitement; + short total_ride_uptime = 0, total_ride_intensity = 0, total_ride_excitement = 0, average_intensity, average_excitement; int num_rides, num_exciting_rides = 0; rct_ride* ride; - // - _ax = 0; num_rides = 0; FOR_ALL_RIDES(i, ride) { - _ax += 100 - ride->var_199; + total_ride_uptime += 100 - ride->downtime; if (ride->excitement != -1){ total_ride_excitement += ride->excitement / 8; @@ -224,7 +221,7 @@ int calculate_park_rating() } result -= 200; if (num_rides > 0) - result += (_ax / num_rides) * 2; + result += (total_ride_uptime / num_rides) * 2; result -= 100; @@ -278,11 +275,11 @@ money32 calculate_ride_value(rct_ride *ride) { if (ride->type == RIDE_TYPE_NULL) return 0; - if (ride->reliability == 0xFFFF) + if (ride->value == RIDE_VALUE_UNDEFINED) return 0; - // Reliability * (...) - return (ride->reliability * 10) * ( + // Fair value * (...) + return (ride->value * 10) * ( ride->var_124 + ride->var_126 + ride->var_128 + ride->var_12A + ride->var_12C + ride->var_12E + ride->age + ride->running_cost + ride->var_134 + ride->var_136 + @@ -333,7 +330,7 @@ money32 calculate_company_value() */ void reset_park_entrances() { - RCT2_GLOBAL(0x013573D4, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id) = 0; for (short i = 0; i < 4; i++) { RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] = 0x8000; @@ -371,8 +368,8 @@ static int park_calculate_guest_generation_probability() suggestedMaxGuests += RCT2_GLOBAL(0x0097D21E + (ride->type * 8), uint8); // Add ride value - if (ride->reliability != RIDE_RELIABILITY_UNDEFINED) { - int rideValue = ride->reliability - ride->price; + if (ride->value != RIDE_VALUE_UNDEFINED) { + int rideValue = ride->value - ride->price; if (rideValue > 0) totalRideValue += rideValue * 2; } @@ -387,9 +384,9 @@ static int park_calculate_guest_generation_probability() if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) continue; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x10000000)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) continue; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x200)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING)) continue; if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) continue; @@ -439,7 +436,7 @@ static int park_calculate_guest_generation_probability() // Reward or penalties for park awards for (i = 0; i < MAX_AWARDS; i++) { - rct_award *award = &RCT2_ADDRESS(RCT2_ADDRESS_AWARD_LIST, rct_award)[i]; + rct_award *award = &gCurrentAwards[i]; if (award->time == 0) continue; @@ -516,7 +513,7 @@ static void park_generate_new_guests() // Extra guests generated by advertising campaigns int campaign; for (campaign = 0; campaign < ADVERTISING_CAMPAIGN_COUNT; campaign++) { - if (RCT2_ADDRESS(0x01358102, uint8)[campaign] != 0) { + if (gMarketingCampaignDaysLeft[campaign] != 0) { // Random chance of guest generation if ((int)(scenario_rand() & 0xFFFF) < marketing_get_campaign_guest_generation_probability(campaign)) park_generate_new_guest_due_to_campaign(campaign); @@ -540,7 +537,7 @@ void park_update() RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, money32) = calculate_company_value(); window_invalidate_by_class(WC_FINANCES); _guestGenerationProbability = park_calculate_guest_generation_probability(); - RCT2_GLOBAL(0x009A9804, uint16) |= 0x10; + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PARK_RATING; window_invalidate_by_class(WC_PARK_INFORMATION); } @@ -581,38 +578,777 @@ void park_update_histories() RCT2_CALLPROC_EBPSAFE(0x0066A231); } -/** -* -* rct2: 0x00669E30 -*/ -void game_command_set_park_entrance_fee() +void park_set_entrance_fee(money32 value) { - uint8 _bl; - uint16 new_fee; - - #ifdef _MSC_VER - __asm mov _bl, bl - #else - __asm__("mov %[_bl], bl " : [_bl] "+m" (_bl)); - #endif - - #ifdef _MSC_VER - __asm mov new_fee, di - #else - __asm__("mov %[new_fee], di " : [new_fee] "+m" (new_fee)); - #endif - - RCT2_GLOBAL(0x0141F56C, uint8) = 0x10; - - if (_bl & 1){ - RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, uint16) = new_fee; + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, 0, GAME_COMMAND_SET_PARK_ENTRANCE_FEE, value, 0); +} +/** + * + * rct2: 0x00669E30 + */ +void game_command_set_park_entrance_fee(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_PARK_ENTRANCE_TICKETS * 4; + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) = (*edi & 0xFFFF); window_invalidate_by_class(WC_PARK_INFORMATION); } + *ebx = 0; +} - #ifdef _MSC_VER - __asm mov ebx, 0 - #else - __asm__("mov ebx, 0 "); - #endif -} \ No newline at end of file +void park_set_open(int open) +{ + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, open << 8, GAME_COMMAND_SET_PARK_OPEN, 0, 0); +} + +/** + * + * rct2: 0x00669D4A + */ +void game_command_set_park_open(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + *ebx = 0; + return; + } + + int dh = (*edx >> 8) & 0xFF; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_PARK_ENTRANCE_TICKETS * 4; + switch (dh) { + case 0: + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_PARK_OPEN; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + break; + case 1: + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN)) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_OPEN; + window_invalidate_by_class(WC_PARK_INFORMATION); + } + break; + case 2: + RCT2_GLOBAL(0x01358838, uint32) = *edi; + window_invalidate_by_class(WC_RIDE); + break; + case 3: + RCT2_GLOBAL(0x0135934C, uint32) = *edi; + window_invalidate_by_class(WC_RIDE); + break; + } + + *ebx = 0; +} + +int park_get_entrance_index(int x, int y, int z) +{ + int i; + + for (i = 0; i < 4; i++) { + if ( + x == RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] && + y == RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, uint16)[i] && + z == RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, uint16)[i] + ) { + return i; + } + } + + return -1; +} + +/** +* +* rct2: 0x006EC847 +*/ +void gfx_invalidate_viewport_tile(int x, int y, int z0, int z1) +{ + int x1, y1, x2, y2; + int tempx; + x += 16; + y += 16; + int rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + switch (rotation) { + case 0: + tempx = x; + x = -x + y; + y += tempx; + break; + case 1: + x = -x; + tempx = x; + x -= y; + y += tempx; + break; + case 2: + tempx = x; + x -= y; + y = -y - tempx; + break; + case 3: + tempx = x; + x += y; + y = -y + tempx; + break; + } + y /= 2; + x2 = x; + y2 = y; + + x -= 32; + y -= 32; + y -= z0; + x2 += 32; + y2 += 32; + y2 += z1; + + x1 = x; + y1 = y; + rct_viewport* viewport = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*); + while (viewport->width != 0) { + int viewport_x2 = viewport->view_x + viewport->view_width; + int viewport_y2 = viewport->view_y + viewport->view_height; + if (x2 > viewport_x2 && y2 > viewport_y2) { + if (x1 < viewport->view_x) + x1 = viewport->view_x; + if (x2 > viewport_x2) + x2 = viewport_x2; + if (y1 < viewport->view_y) + y1 = viewport->view_y; + if (y2 > viewport_y2) + y2 = viewport_y2; + + uint8 zoom = 1 << viewport->zoom; + x1 -= viewport->view_x; + y1 -= viewport->view_y; + x2 -= viewport->view_x; + y2 -= viewport->view_y; + x1 /= zoom; + y1 /= zoom; + x2 /= zoom; + y2 /= zoom; + x1 += viewport->x; + y1 += viewport->y; + x2 += viewport->x; + y2 += viewport->y; + gfx_set_dirty_blocks(x1, y1, x2, y2); + } + viewport++; + } +} + +/** +* +* rct2: 0x00664D05 +*/ +void update_park_fences(int x, int y) +{ + if (x > 0x1FFF) + return; + if (y > 0x1FFF) + return; + + rct_map_element* sufaceElement = map_get_surface_element_at(x / 32, y / 32); + if (sufaceElement == NULL)return; + + uint8 newOwnership = sufaceElement->properties.surface.ownership & 0xF0; + if ((sufaceElement->properties.surface.ownership & OWNERSHIP_OWNED) == 0) { + uint8 fence_required = 1; + + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + // If an entrance element do not place flags around surface + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + if (!(mapElement->flags & MAP_ELEMENT_FLAG_GHOST)) { + fence_required = 0; + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + if (fence_required) { + // As map_is_location_in_park sets the error text + // will require to back it up. + rct_string_id previous_error = RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id); + if (map_is_location_in_park(x - 32, y)){ + newOwnership |= 0x8; + } + + if (map_is_location_in_park(x, y - 32)){ + newOwnership |= 0x4; + } + + if (map_is_location_in_park(x + 32, y)){ + newOwnership |= 0x2; + } + + if (map_is_location_in_park(x, y + 32)){ + newOwnership |= 0x1; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = previous_error; + } + } + + if (sufaceElement->properties.surface.ownership != newOwnership) { + int z0 = sufaceElement->base_height * 8; + int z1 = z0 + 16; + gfx_invalidate_viewport_tile(x, y, z0, z1); + sufaceElement->properties.surface.ownership = newOwnership; + } +} + +void park_remove_entrance_segment(int x, int y, int z) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (mapElement->base_height != z) + continue; + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) + continue; + + gfx_invalidate_viewport_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + map_element_remove(mapElement); + update_park_fences(x, y); + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * + * rct2: 0x00666A63 + */ +void game_command_remove_park_entrance(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + int x, y, z, entranceIndex, direction; + + x = *eax & 0xFFFF; + y = *ecx & 0xFFFF; + z = *edx * 16; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint32) = RCT_EXPENDITURE_TYPE_LAND_PURCHASE * 4; + RCT2_GLOBAL(0x009DEA5E, uint16) = x; + RCT2_GLOBAL(0x009DEA60, uint16) = y; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + + if (!(*ebx & GAME_COMMAND_FLAG_APPLY)) { + *ebx = 0; + return; + } + + entranceIndex = park_get_entrance_index(x, y, z); + if (entranceIndex == -1) { + *ebx = 0; + return; + } + + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[entranceIndex] = 0x8000; + direction = (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[entranceIndex] - 1) & 3; + z = (*edx & 0xFF) * 2; + + // Centre (sign) + park_remove_entrance_segment(x, y, z); + + // Left post + park_remove_entrance_segment( + x + TileDirectionDelta[direction].x, + y + TileDirectionDelta[direction].y, + z + ); + + // Right post + park_remove_entrance_segment( + x - TileDirectionDelta[direction].x, + y - TileDirectionDelta[direction].y, + z + ); + + *ebx = 0; +} + +void park_set_name(const char *name) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_RENAME_PARK; + game_do_command(1, GAME_COMMAND_FLAG_APPLY, 0, *((int*)(name + 0)), GAME_COMMAND_SET_PARK_NAME, *((int*)(name + 8)), *((int*)(name + 4))); + game_do_command(2, GAME_COMMAND_FLAG_APPLY, 0, *((int*)(name + 12)), GAME_COMMAND_SET_PARK_NAME, *((int*)(name + 20)), *((int*)(name + 16))); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, *((int*)(name + 24)), GAME_COMMAND_SET_PARK_NAME, *((int*)(name + 32)), *((int*)(name + 28))); +} + +/** + * + * rct2: 0x00669C6D + */ +void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + rct_string_id newUserStringId; + char oldName[128]; + static char newName[128]; + + int nameChunkIndex = *eax & 0xFFFF; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + int nameChunkOffset = nameChunkIndex - 1; + if (nameChunkOffset < 0) + nameChunkOffset = 2; + nameChunkOffset *= 12; + RCT2_GLOBAL(newName + nameChunkOffset + 0, uint32) = *edx; + RCT2_GLOBAL(newName + nameChunkOffset + 4, uint32) = *ebp; + RCT2_GLOBAL(newName + nameChunkOffset + 8, uint32) = *edi; + } + + if (nameChunkIndex != 0) { + *ebx = 0; + return; + } + + format_string(oldName, RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id), &RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32)); + if (strcmp(oldName, newName) == 0) { + *ebx = 0; + return; + } + + if (newName[0] == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_INVALID_RIDE_ATTRACTION_NAME; + *ebx = MONEY32_UNDEFINED; + return; + } + + newUserStringId = user_string_allocate(4, newName); + if (newUserStringId == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_INVALID_NAME_FOR_PARK; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + // Free the old ride name + user_string_free(RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id)); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id) = newUserStringId; + + gfx_invalidate_screen(); + } else { + user_string_free(newUserStringId); + } + + *ebx = 0; +} + +int map_buy_land_rights_for_tile(int x, int y, int setting, int flags) { + int y2; + int cost; + int tile_idx; + + y2 = y; + cost = 0; + tile_idx = (((y & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + while ((TILE_MAP_ELEMENT_POINTER(tile_idx)->type & 0x3C) != 0) { + y2 += 8; + tile_idx = (((y2 & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + } + uint8 ownership = TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership; + switch (setting) { + case 0: + if ((ownership & OWNERSHIP_OWNED) != 0) { // If the land is already owned + cost = 0; + return cost; + } + else if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (ownership & OWNERSHIP_AVAILABLE) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1726; // Land not for sale! + cost = 0;// MONEY32_UNDEFINED; + return cost; + } + else { + if ((flags & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_OWNED; + update_park_fences(x, y); + update_park_fences(x - 32, y); + update_park_fences(x + 32, y); + update_park_fences(x, y + 32); + update_park_fences(x, y - 32); + } + cost = RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, uint16); + return cost; + } + break; + case 1: + if ((flags & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership &= 0xCF; + update_park_fences(x, y); + update_park_fences(x - 32, y); + update_park_fences(x + 32, y); + update_park_fences(x, y + 32); + update_park_fences(x, y - 32); + } + cost = 0; + break; + case 2: + if ((ownership & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) { // If the land or construction rights are already owned + cost = 0; + return cost; + } + else if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1727; // Construction rights not for sale! + cost = 0;// MONEY32_UNDEFINED; + return cost; + } + else { + if ((flags & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y, baseHeight, baseHeight + 16); + } + cost = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, uint16); + return cost; + } + break; + case 3: + if ((flags & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership &= 0xEF; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y, baseHeight, baseHeight + 16); + } + cost = 0; + break; + break; + case 4: + if ((flags & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_AVAILABLE; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y, baseHeight, baseHeight + 16); + } + cost = 0; + break; + case 5: + if ((flags & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y, baseHeight, baseHeight + 16); + } + cost = 0; + break; + default: + if (x <= 32) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3215; + cost = 0;// MONEY32_UNDEFINED; + return cost; + } + else if (y <= 32) { + int ebp = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16); + ebp -= 32; + if (x >= ebp || y >= ebp) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3215; + cost = 0;// MONEY32_UNDEFINED; + return cost; + } + else { + int tile_idx2 = (((y & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + ownership = TILE_MAP_ELEMENT_POINTER(tile_idx2)->properties.surface.ownership; + y2 = y; + do { + y2 += 8; + tile_idx2 = (((y2 & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + if ((TILE_MAP_ELEMENT_POINTER(tile_idx2)->type & 0x3C) == 0x10) { + cost = 0; + return cost; + } + + } while ((TILE_MAP_ELEMENT_POINTER(((((y - 8) & 0xFFE0) * 256) + (x & 0xFFE0)) / 32)->flags & 0x80) == 0); + + uint8 bh = (flags & 0xFF00) >> 4; + if (bh == (TILE_MAP_ELEMENT_POINTER(tile_idx2)->properties.surface.ownership & 0xF0)) { + cost = 0; + return cost; + } + else { + if ((cost & 1) == 0) { + cost = RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, uint16); + return cost; + } + if ((bh & 0xF0) == 0) { + uint16 bp = RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS, uint16); + if (x != (bp & 0xFFE0)) { + bp = RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS + 2, uint16); + if (y != (bp & 0xFFE0)) { + RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS, uint16) = 0xFFFF; + } + } + bp = RCT2_GLOBAL(0x13573F8, uint16); + if (x != (bp & 0xFFE0)) { + bp = RCT2_GLOBAL(0x13573F8 + 2, uint16); + if (y != (bp & 0xFFE0)) { + RCT2_GLOBAL(0x13573F8, uint16) = 0xFFFF; + } + } + } + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership &= 0x0F; + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= bh; + update_park_fences(x, y); + update_park_fences(x - 32, y); + update_park_fences(x + 32, y); + update_park_fences(x, y + 32); + update_park_fences(x, y - 32); + RCT2_GLOBAL(0x9E2E28, uint8) |= 1; + + cost = 0; + return cost; + } + } + } + break; + } + return cost; +} + +int map_buy_land_rights(int x0, int y0, int x1, int y1, int setting, int flags) +{ + int x, y, z; + money32 totalCost, cost; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LAND_PURCHASE * 4; + + if (x1 == 0 && y1 == 0) { + x1 = x0; + y1 = y0; + } + + x = (x0 + x1) / 2 + 16; + y = (y0 + y1) / 2 + 16; + z = map_element_height(x, y); + RCT2_GLOBAL(0x009DEA5E, uint16) = x; + RCT2_GLOBAL(0x009DEA60, uint16) = y; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + + // Game command modified to accept selection size + totalCost = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0 || gConfigCheat.build_in_pause_mode) { + for (y = y0; y <= y1; y += 32) { + for (x = x0; x <= x1; x += 32) { + cost = map_buy_land_rights_for_tile(x, y, setting, flags); + if (cost == MONEY32_UNDEFINED) + return MONEY32_UNDEFINED; + + totalCost += cost; + } + } + } + + return totalCost; +} + +/** +* +* rct2: 0x006649BD +*/ +void game_command_buy_land_rights(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = map_buy_land_rights( + (*eax & 0xFFFF), + (*ecx & 0xFFFF), + (*edi & 0xFFFF), + (*ebp & 0xFFFF), + (*edx & 0xFF00) >> 8, + *ebx & 0xFF + ); + // Original decompiled function for Duncan to look at: + + /*RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LAND_PURCHASE * 4; + int x = *eax; + int y = *ecx; + int y2 = *ecx; + int z = map_element_height(x + 16, y + 16); + + RCT2_GLOBAL(0x009DEA5E, uint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, uint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, uint16) = z; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) { + + int tile_idx = (((y & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + while ((TILE_MAP_ELEMENT_POINTER(tile_idx)->type & 0x3C) != 0) { + y += 8; + tile_idx = (((y & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + } + uint8 ownership = TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership; + uint8 flags = (*edx & 0xFF00) >> 8; + switch (flags) { + case 0: + if ((ownership & OWNERSHIP_OWNED) != 0) { // If the land is already owned + *ebx = 0; + return; + } + else if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (ownership & OWNERSHIP_AVAILABLE) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1726; // Land not for sale! + *ebx = 0x80000000; + return; + } + else { + if ((*ebx & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_OWNED; + update_park_fences(x, y2); + update_park_fences(x - 32, y2); + update_park_fences(x + 32, y2); + update_park_fences(x, y2 + 32); + update_park_fences(x, y2 - 32); + } + *ebx = RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, uint16); + return; + } + break; + case 1: + if ((*ebx & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership &= 0xCF; + update_park_fences(x, y2); + update_park_fences(x - 32, y2); + update_park_fences(x + 32, y2); + update_park_fences(x, y2 + 32); + update_park_fences(x, y2 - 32); + } + *ebx = 0; + break; + case 2: + if ((ownership & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) { // If the land or construction rights are already owned + *ebx = 0; + return; + } + else if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1727; // Construction rights not for sale! + *ebx = 0x80000000; + return; + } + else { + if ((*ebx & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y2, baseHeight, baseHeight + 16); + } + *ebx = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, uint16); + return; + } + break; + case 3: + if ((*ebx & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership &= 0xEF; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y2, baseHeight, baseHeight + 16); + } + *ebx = 0; + break; + break; + case 4: + if ((*ebx & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_AVAILABLE; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y2, baseHeight, baseHeight + 16); + } + *ebx = 0; + break; + case 5: + if ((*ebx & 1) != 0) { + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE; + uint16 baseHeight = TILE_MAP_ELEMENT_POINTER(tile_idx)->base_height; + baseHeight *= 8; + gfx_invalidate_viewport_tile(x, y2, baseHeight, baseHeight + 16); + } + *ebx = 0; + break; + default: + if (x <= 32) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3215; + *ebx = 0x80000000; + return; + } + else if (y <= 32) { + *ebp = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16); + *ebp -= 32; + if (x >= *ebp || y >= *ebp) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3215; + *ebx = 0x80000000; + return; + } + else { + int tile_idx2 = (((y & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + ownership = TILE_MAP_ELEMENT_POINTER(tile_idx2)->properties.surface.ownership; + do { + y += 8; + tile_idx2 = (((y & 0xFFE0) * 256) + (x & 0xFFE0)) / 32; + if ((TILE_MAP_ELEMENT_POINTER(tile_idx2)->type & 0x3C) == 0x10) { + *ebx = 0; + return; + } + + } while ((TILE_MAP_ELEMENT_POINTER(((((y - 8) & 0xFFE0) * 256) + (x & 0xFFE0)) / 32)->flags & 0x80) == 0); + + uint8 bh = (*ebx & 0xFF00) >> 4; + if (bh == (TILE_MAP_ELEMENT_POINTER(tile_idx2)->properties.surface.ownership & 0xF0)) { + *ebx = 0; + return; + } + else { + if ((*ebx & 1) == 0) { + *ebx = RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, uint16); + return; + } + if ((bh & 0xF0) == 0) { + uint16 bp = RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS, uint16); + if (x != (bp & 0xFFE0)) { + bp = RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS + 2, uint16); + if (y2 != (bp & 0xFFE0)) { + RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS, uint16) = 0xFFFF; + } + } + bp = RCT2_GLOBAL(0x13573F8, uint16); + if (x != (bp & 0xFFE0)) { + bp = RCT2_GLOBAL(0x13573F8 + 2, uint16); + if (y2 != (bp & 0xFFE0)) { + RCT2_GLOBAL(0x13573F8, uint16) = 0xFFFF; + } + } + } + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership &= 0x0F; + TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= bh; + update_park_fences(x, y2); + update_park_fences(x - 32, y2); + update_park_fences(x + 32, y2); + update_park_fences(x, y2 + 32); + update_park_fences(x, y2 - 32); + RCT2_GLOBAL(0x9E2E28, uint8) |= 1; + + *ebx = 0; + return; + } + } + } + break; + } + } + else { + // Should this ever be called? esi is never set properly + if ((*ebx & 1) != 0) { + //TILE_MAP_ELEMENT_POINTER(tile_idx)->properties.surface.ownership |= OWNERSHIP_OWNED; + update_park_fences(x, y); + update_park_fences(x - 32, y2); + update_park_fences(x + 32, y2); + update_park_fences(x, y2 + 32); + update_park_fences(x, y2 - 32); + } + *ebx = RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, uint16); + }*/ +} diff --git a/src/world/park.h b/src/world/park.h index dc1ef66b03..3bdab3fc5e 100644 --- a/src/world/park.h +++ b/src/world/park.h @@ -35,13 +35,14 @@ enum { PARK_FLAGS_FORBID_HIGH_CONSTRUCTION = (1 << 5), // below tree height PARK_FLAGS_PREF_LESS_INTENSE_RIDES = (1 << 6), PARK_FLAGS_FORBID_MARKETING_CAMPAIGN = (1 << 7), - PARK_FLAGS_PREF_MORE_INTENSE_RIDES = (1 << 8), + PARK_FLAGS_PREF_MORE_INTENSE_RIDES = (1 << 9), PARK_FLAGS_NO_MONEY = (1 << 11), PARK_FLAGS_DIFFICULT_GUEST_GENERATION = (1 << 12), PARK_FLAGS_PARK_FREE_ENTRY = (1 << 13), PARK_FLAGS_DIFFICULT_PARK_RATING = (1 << 14), PARK_FLAGS_NO_MONEY_SCENARIO = (1 << 17), // equivalent to PARK_FLAGS_NO_MONEY, but used in scenario editor - PARK_FLAGS_18 = (1 << 18) + PARK_FLAGS_18 = (1 << 18), + PARK_FLAGS_SIX_FLAGS = (1 << 19) }; int park_is_open(); @@ -60,6 +61,17 @@ void park_update_histories(); uint8 calculate_guest_initial_happiness(uint8 percentage); -void game_command_set_park_entrance_fee(); +void park_set_open(int open); +int park_get_entrance_index(int x, int y, int z); +void park_set_name(const char *name); +void park_set_entrance_fee(money32 value); + +void game_command_set_park_entrance_fee(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_park_open(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_remove_park_entrance(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_buy_land_rights(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); + +void gfx_invalidate_viewport_tile(int x, int y, int z0, int z1); #endif diff --git a/src/world/scenery.c b/src/world/scenery.c new file mode 100644 index 0000000000..3a05927927 --- /dev/null +++ b/src/world/scenery.c @@ -0,0 +1,198 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#include "../addresses.h" +#include "../game.h" +#include "../common.h" +#include "../localisation/localisation.h" +#include "../scenario.h" +#include "climate.h" +#include "fountain.h" +#include "map.h" +#include "park.h" +#include "scenery.h" + +void scenery_increase_age(int x, int y, rct_map_element *mapElement); + +void scenery_update_tile(int x, int y) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SCENERY) { + scenery_update_age(x, y, mapElement); + } else if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { + int additions = mapElement->properties.path.additions & 0x0F; + if (additions != 0 && !(mapElement->properties.path.additions & 0x80)) { + rct_scenery_entry *sceneryEntry; + sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (sceneryEntry->path_bit.var_06 & PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER) { + jumping_fountain_begin(JUMPING_FOUNTAIN_TYPE_WATER, x, y, mapElement); + } else if (sceneryEntry->path_bit.var_06 & PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW) { + jumping_fountain_begin(JUMPING_FOUNTAIN_TYPE_SNOW, x, y, mapElement); + } + } + } + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * + * rct2: 0x006E33D9 + */ +void scenery_update_age(int x, int y, rct_map_element *mapElement) +{ + rct_map_element *mapElementAbove; + rct_scenery_entry *sceneryEntry; + + sceneryEntry = g_smallSceneryEntries[mapElement->properties.scenery.type]; + if ( + !(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_CAN_BE_WATERED) || + (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER, uint8) < WEATHER_RAIN) || + (mapElement->properties.scenery.age < 5) + ) { + scenery_increase_age(x, y, mapElement); + return; + } + + // Check map elements above, presumebly to see if map element is blocked from rain + mapElementAbove = mapElement; + while (!(mapElementAbove->flags & 7)) { + mapElementAbove++; + + switch (map_element_get_type(mapElementAbove)) { + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + case MAP_ELEMENT_TYPE_ENTRANCE: + case MAP_ELEMENT_TYPE_PATH: + map_invalidate_tile(x, y, mapElementAbove->base_height * 8, mapElementAbove->clearance_height * 8); + scenery_increase_age(x, y, mapElement); + return; + case MAP_ELEMENT_TYPE_SCENERY: + sceneryEntry = g_smallSceneryEntries[mapElementAbove->properties.scenery.type]; + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE) { + scenery_increase_age(x, y, mapElement); + return; + } + break; + } + } + + // Reset age / water plant + mapElement->properties.scenery.age = 0; + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); +} + +void scenery_increase_age(int x, int y, rct_map_element *mapElement) +{ + if (mapElement->flags & SMALL_SCENERY_FLAG_ANIMATED) + return; + + if (mapElement->properties.scenery.age < 255) { + mapElement->properties.scenery.age++; + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + } +} + + +/* 0x006E2712 */ +void scenery_remove_ghost_tool_placement(){ + sint16 x, y, z; + + x = RCT2_GLOBAL(0x00F64EC4, sint16); + y = RCT2_GLOBAL(0x00F64EC6, sint16); + z = RCT2_GLOBAL(0x00F64F09, uint8); + + if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 0)){ + RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 0); + + game_do_command( + x, + 105 | (RCT2_GLOBAL(0x00F64F0C, uint8) << 8), + y, + z | (RCT2_GLOBAL(0x00F64EDA, uint8) << 8), + GAME_COMMAND_REMOVE_SCENERY, + 0, + 0); + } + + if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 1)){ + RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 1); + + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_PATH) + continue; + + if (map_element->base_height != z) + continue; + + game_do_command( + x, + 233 | (RCT2_GLOBAL(0x00F64F0F, uint8) << 8), + y, + z | (RCT2_GLOBAL(0x00F64F10, uint8) << 8), + GAME_COMMAND_PLACE_PATH, + RCT2_GLOBAL(0x00F64EAC, uint32) & 0xFFFF0000, + 0); + break; + } while (!map_element_is_last_for_tile(map_element++)); + } + + if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 2)){ + RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 2); + + game_do_command( + x, + 105 | (RCT2_GLOBAL(0x00F64F0C, uint8) << 8), + y, + RCT2_GLOBAL(0x00F64F11, uint8) |(z << 8), + GAME_COMMAND_REMOVE_FENCE, + 0, + 0); + } + + if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 3)){ + RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 3); + + game_do_command( + x, + 105 | (RCT2_GLOBAL(0x00F64EC0, uint8) << 8), + y, + z, + GAME_COMMAND_REMOVE_LARGE_SCENERY, + 0, + 0); + } + + if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 4)){ + RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 4); + + game_do_command( + x, + 105, + y, + z | (RCT2_GLOBAL(0x00F64EC0, uint8) << 8), + GAME_COMMAND_REMOVE_BANNER, + 0, + 0); + } +} \ No newline at end of file diff --git a/src/world/scenery.h b/src/world/scenery.h index 744f414e8b..c35704f13d 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -22,47 +22,66 @@ #define _SCENERY_H_ #include "../common.h" +#include "../object.h" typedef struct { uint32 flags; // 0x06 uint8 height; // 0x0A uint8 tool_id; // 0x0B - uint16 price; // 0x0C + sint16 price; // 0x0C sint16 removal_price; // 0x0E - uint8 pad_10[0x0A]; + uint32 var_10; + uint8 pad_14[0x06]; uint8 scenery_tab_id; // 0x1A } rct_small_scenery_entry; typedef enum { - SMALL_SCENERY_FLAG1 = (1 << 0), // 0x1 - SMALL_SCENERY_FLAG2 = (1 << 1), // 0x2 - SMALL_SCENERY_FLAG3 = (1 << 2), // 0x4 - SMALL_SCENERY_FLAG4 = (1 << 3), // 0x8 - SMALL_SCENERY_FLAG5 = (1 << 4), // 0x10 - SMALL_SCENERY_FLAG6 = (1 << 5), // 0x20 - SMALL_SCENERY_FLAG7 = (1 << 6), // 0x40 - SMALL_SCENERY_FLAG8 = (1 << 7), // 0x80 - SMALL_SCENERY_FLAG9 = (1 << 8), // 0x100 - SMALL_SCENERY_FLAG10 = (1 << 9), // 0x200 - SMALL_SCENERY_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400 - SMALL_SCENERY_FLAG12 = (1 << 11), // 0x800 - SMALL_SCENERY_FLAG13 = (1 << 12), // 0x1000 - SMALL_SCENERY_FLAG14 = (1 << 13), // 0x2000 - SMALL_SCENERY_FLAG15 = (1 << 14), // 0x4000 - SMALL_SCENERY_FLAG16 = (1 << 15), // 0x8000 - SMALL_SCENERY_FLAG17 = (1 << 16), // 0x10000 - SMALL_SCENERY_FLAG18 = (1 << 17), // 0x20000 - SMALL_SCENERY_FLAG19 = (1 << 18), // 0x40000 - SMALL_SCENERY_HAS_SECONDARY_COLOUR = (1 << 19), // 0x80000 + SMALL_SCENERY_FLAG_FULL_TILE = (1 << 0), // 0x1 + SMALL_SCENERY_FLAG_VOFFSET_CENTRE = (1 << 1), // 0x2 + SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE = (1 << 2), // 0x4 + SMALL_SCENERY_FLAG4 = (1 << 3), // 0x8 + SMALL_SCENERY_FLAG_ANIMATED = (1 << 4), // 0x10 + SMALL_SCENERY_FLAG6 = (1 << 5), // 0x20 + SMALL_SCENERY_FLAG_CAN_BE_WATERED = (1 << 6), // 0x40 + SMALL_SCENERY_FLAG8 = (1 << 7), // 0x80 + SMALL_SCENERY_FLAG9 = (1 << 8), // 0x100 + SMALL_SCENERY_FLAG10 = (1 << 9), // 0x200 + SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400 + SMALL_SCENERY_FLAG12 = (1 << 11), // 0x800 + SMALL_SCENERY_FLAG13 = (1 << 12), // 0x1000 + SMALL_SCENERY_FLAG_IS_CLOCK = (1 << 13), // 0x2000 + SMALL_SCENERY_FLAG15 = (1 << 14), // 0x4000 + SMALL_SCENERY_FLAG16 = (1 << 15), // 0x8000 + SMALL_SCENERY_FLAG17 = (1 << 16), // 0x10000 + SMALL_SCENERY_FLAG18 = (1 << 17), // 0x20000 + SMALL_SCENERY_FLAG19 = (1 << 18), // 0x40000 + SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 19), // 0x80000 + SMALL_SCENERY_FLAG20 = (1 << 20), // 0x100000 + SMALL_SCENERY_FLAG21 = (1 << 21), // 0x200000 + SMALL_SCENERY_FLAG22 = (1 << 22), // 0x400000 + SMALL_SCENERY_FLAG23 = (1 << 23), // 0x800000 + SMALL_SCENERY_FLAG24 = (1 << 24), // 0x1000000 + SMALL_SCENERY_FLAG25 = (1 << 25), // 0x2000000 } SMALL_SCENERY_FLAGS; +typedef struct { + sint16 x_offset; + sint16 y_offset; + sint16 z_offset; + uint8 var_6; + uint16 var_7; +} rct_large_scenery_tile; + typedef struct { uint8 tool_id; // 0x06 uint8 flags; // 0x07 - uint16 price; // 0x08 - uint8 pad_0A[6]; + sint16 price; // 0x08 + sint16 removal_price; // 0x0A + rct_large_scenery_tile* tiles; // 0x0C uint8 scenery_tab_id; // 0x10 uint8 var_11; + uint32 var_12; + uint32 var_16; } rct_large_scenery_entry; @@ -71,7 +90,7 @@ typedef struct { uint8 flags; // 0x07 uint8 height; // 0x08 uint8 flags2; // 0x09 - uint16 price; // 0x0A + sint16 price; // 0x0A uint8 scenery_tab_id; // 0x0C uint8 var_0D; } rct_wall_scenery_entry; @@ -88,16 +107,17 @@ typedef enum { } WALL_SCENERY_FLAGS; typedef struct { - uint8 pad_02[3]; + uint16 var_06; + uint8 pad_08; uint8 tool_id; // 0x09 - uint16 price; // 0x0A + sint16 price; // 0x0A uint8 scenery_tab_id; // 0x0C } rct_path_bit_scenery_entry; typedef struct { uint8 var_06; uint8 flags; // 0x07 - uint16 price; // 0x08 + sint16 price; // 0x08 uint8 scenery_tab_id; // 0x0A } rct_banner_scenery_entry; @@ -118,19 +138,45 @@ typedef struct { uint32 image; // 0x02 uint16 scenery_entries[0x80]; // 0x06 uint8 entry_count; // 0x106 - uint8 pad_107; + uint8 var_107; uint8 var_108; // 0x108, order? uint8 pad_109; uint32 var_10A; } rct_scenery_set_entry; -#define g_smallSceneryEntries RCT2_ADDRESS(RCT2_ADDRESS_SMALL_SCENERY_ENTRIES, rct_scenery_entry*) -#define g_largeSceneryEntries RCT2_ADDRESS(RCT2_ADDRESS_LARGE_SCENERY_ENTRIES, rct_scenery_entry*) -#define g_wallSceneryEntries RCT2_ADDRESS(RCT2_ADDRESS_WALL_SCENERY_ENTRIES, rct_scenery_entry*) -#define g_bannerSceneryEntries RCT2_ADDRESS(RCT2_ADDRESS_BANNER_SCENERY_ENTRIES, rct_scenery_entry*) -#define g_pathBitSceneryEntries RCT2_ADDRESS(RCT2_ADDRESS_PATH_BIT_SCENERY_ENTRIES, rct_scenery_entry*) -#define g_scenerySetEntries RCT2_ADDRESS(RCT2_ADDRESS_SCENERY_SET_ENTRIES, rct_scenery_set_entry*) +enum { + PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER = 1 << 4, + PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW = 1 << 5 +}; + +#define SCENERY_ENTRIES_BY_TAB 128 + +#define g_smallSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].chunks) +#define g_largeSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_LARGE_SCENERY].chunks) +#define g_wallSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_WALLS].chunks) +#define g_bannerSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_BANNERS].chunks) + +// Often 0x009ADA50 is used for pathBits this is 1 entry before g_pathBitSceneryEntries and is used +// because 0 represents no path bits on a path. So remember to remove 1 when using it for 0x009ADA50 +#define g_pathBitSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_PATH_BITS].chunks) +#define g_scenerySetEntries ((rct_scenery_set_entry**)object_entry_groups[OBJECT_TYPE_SCENERY_SETS].chunks) + +#define window_scenery_active_tab_index RCT2_GLOBAL(0x00F64EDC, uint8) +#define window_scenery_selected_scenery_by_tab RCT2_ADDRESS(0x00F64EDD, sint16) +#define window_scenery_is_build_cluster_tool_on RCT2_GLOBAL(0x00F64F1A, uint8) +#define window_scenery_is_repaint_scenery_tool_on RCT2_GLOBAL(0x00F64F19, uint8) +#define window_scenery_rotation RCT2_GLOBAL(0x00F64F05, uint8) +#define window_scenery_primary_colour RCT2_GLOBAL(0x00F64F06, uint8) +#define window_scenery_secondary_colour RCT2_GLOBAL(0x00F64F07, uint8) +#define window_scenery_tertiary_colour RCT2_GLOBAL(0x00F64F08, uint8) + +extern sint16 window_scenery_tab_entries[20][SCENERY_ENTRIES_BY_TAB + 1]; void init_scenery(); +void scenery_update_tile(int x, int y); +void scenery_update_age(int x, int y, rct_map_element *mapElement); +void scenery_set_default_placement_configuration(); +void scenery_remove_ghost_tool_placement(); +void scenery_set_default_placement_configuration(); #endif \ No newline at end of file diff --git a/src/world/sprite.c b/src/world/sprite.c index b21927e1e3..ede41f10d8 100644 --- a/src/world/sprite.c +++ b/src/world/sprite.c @@ -19,21 +19,512 @@ *****************************************************************************/ #include "../addresses.h" +#include "../audio/audio.h" #include "../interface/viewport.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../scenario.h" +#include "fountain.h" #include "sprite.h" +enum { + DUCK_STATE_FLY_TO_WATER, + DUCK_STATE_SWIM, + DUCK_STATE_DRINK, + DUCK_STATE_DOUBLE_DRINK, + DUCK_STATE_FLY_AWAY +}; + rct_sprite* g_sprite_list = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite); +static void duck_update_fly_to_water(rct_duck *duck); +static void duck_update_swim(rct_duck *duck); +static void duck_update_drink(rct_duck *duck); +static void duck_update_double_drink(rct_duck *duck); +static void duck_update_fly_away(rct_duck *duck); + /** * * rct2: 0x006736C7 */ -void create_balloon(int x, int y, int z, int colour) +void create_balloon(int x, int y, int z, int colour, uint8 bl) { - RCT2_CALLPROC_X(0x006736C7, x, colour << 8, y, z, 0, 0, 0); + rct_sprite* sprite = create_sprite(2); + if (sprite != NULL) + { + sprite->balloon.var_14 = 13; + sprite->balloon.var_09 = 22; + sprite->balloon.var_15 = 11; + sprite->balloon.sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite_move(x, y, z, sprite); + sprite->balloon.misc_identifier = SPRITE_MISC_BALLOON; + sprite->balloon.var_26 = 0; + sprite->balloon.colour = colour; + sprite->balloon.popped = bl; + } } -/* rct2: 0x006EC473 */ +void balloon_pop(rct_balloon *balloon) +{ + balloon->popped = 1; + balloon->var_26 = 0; + sound_play_panned(SOUND_BALLOON_POP, 0x8001, balloon->x, balloon->y, balloon->z); +} + +/** + * + * rct: 0x0067342C + */ +void balloon_update(rct_balloon *balloon) +{ + invalidate_sprite((rct_sprite*)balloon); + if (balloon->popped == 1) { + balloon->var_26 += 256; + if (balloon->var_26 >= 1280) + sprite_remove((rct_sprite*)balloon); + + return; + } + + int original_var26a = balloon->var_26a; + balloon->var_26a += 85; + if (original_var26a < 255 - 85) + return; + + balloon->var_26b++; + sprite_move(balloon->x, balloon->y, balloon->z + 1, (rct_sprite*)balloon); + + int maxZ = 1967 - ((balloon->x ^ balloon->y) & 31); + if (balloon->z < maxZ) + return; + + balloon_pop(balloon); +} + +/** + * + * rct2: 0x006E88ED + */ +void balloon_press(rct_balloon *balloon) +{ + if (balloon->popped == 1) + return; + + uint32 random = scenario_rand(); + if ((balloon->var_0A & 7) || (random & 0xFFFF) < 0x2000) { + balloon_pop(balloon); + return; + } + + sprite_move( + balloon->x + ((random & 0x80000000) ? -6 : 6), + balloon->y, + balloon->z, + (rct_sprite*)balloon + ); +} + +// rct2: 0x009A3B04 +static const rct_xy16 duck_move_offset[] = { + { -1, 0 }, + { 0, 1 }, + { 1, 0 }, + { 0, -1 } +}; + +// rct2: 0x0097F073 +static const uint8 duck_drink_animation[] = { + 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 255 +}; + +// rct2: 0x0097F08C +static const uint8 duck_double_drink_animation[] = { + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 0, 0, 0, 0, 255 +}; + +/** + * + * rct2: 0x0067440F + */ +void create_duck(int targetX, int targetY) +{ + rct_sprite* sprite = create_sprite(2); + if (sprite != NULL) { + sprite->duck.sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite->duck.misc_identifier = SPRITE_MISC_DUCK; + sprite->duck.var_14 = 9; + sprite->duck.var_09 = 0xC; + sprite->duck.var_15 = 9; + int offset_xy = scenario_rand() & 0x1E; + targetX += offset_xy; + targetY += offset_xy; + sprite->duck.target_x = targetX; + sprite->duck.target_y = targetY; + uint8 direction = scenario_rand() & 3; + switch (direction) + { + case 0: + targetX = 8191 - (scenario_rand() & 0x3F); + break; + case 1: + targetY = scenario_rand() & 0x3F; + break; + case 2: + targetX = scenario_rand() & 0x3F; + break; + case 3: + targetY = 8191 - (scenario_rand() & 0x3F); + break; + } + sprite->duck.sprite_direction = direction << 3; + sprite_move(targetX, targetY, 496, sprite); + sprite->duck.state = DUCK_STATE_FLY_TO_WATER; + sprite->duck.var_26 = 0; + } +} + +/** + * + * rct: 0x006740E8 + */ +void duck_update(rct_duck *duck) +{ + switch (duck->state) { + case DUCK_STATE_FLY_TO_WATER: + duck_update_fly_to_water(duck); + break; + case DUCK_STATE_SWIM: + duck_update_swim(duck); + break; + case DUCK_STATE_DRINK: + duck_update_drink(duck); + break; + case DUCK_STATE_DOUBLE_DRINK: + duck_update_double_drink(duck); + break; + case DUCK_STATE_FLY_AWAY: + duck_update_fly_away(duck); + break; + } +} + +static void duck_invalidate(rct_duck *duck) +{ + sub_6EC60B((rct_sprite*)duck); +} + +/** + * + * rct: 0x00674108 + */ +static void duck_update_fly_to_water(rct_duck *duck) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3) + return; + + duck->var_26++; + if (duck->var_26 >= 6) + duck->var_26 = 0; + + duck_invalidate(duck); + int manhattanDistance = abs(duck->target_x - duck->x) + abs(duck->target_y - duck->y); + int direction = duck->sprite_direction >> 3; + int x = duck->x + duck_move_offset[direction].x; + int y = duck->y + duck_move_offset[direction].y; + int manhattanDistanceN = abs(duck->target_x - x) + abs(duck->target_y - y); + + rct_map_element *mapElement = map_get_surface_element_at(duck->target_x >> 5, duck->target_y >> 5); + int waterHeight = mapElement->properties.surface.terrain & 0x1F; + if (waterHeight == 0) { + duck->state = DUCK_STATE_FLY_AWAY; + duck_update_fly_away(duck); + return; + } + waterHeight <<= 4; + int z = abs(duck->z - waterHeight); + + if (manhattanDistanceN <= manhattanDistance) { + if (z > manhattanDistanceN) { + z = duck->z - 2; + if (waterHeight >= duck->z) + z += 4; + + duck->var_26 = 1; + } else { + z = duck->z; + } + sprite_move(x, y, z, (rct_sprite*)duck); + duck_invalidate(duck); + } else { + if (z > 4) { + duck->state = DUCK_STATE_FLY_AWAY; + duck_update_fly_away(duck); + } else { + duck->state = DUCK_STATE_SWIM; + duck->var_26 = 0; + duck_update_swim(duck); + } + } +} + +/** + * + * rct: 0x00674282 + */ +static void duck_update_swim(rct_duck *duck) +{ + if ((RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) + duck->var_0A) & 3) + return; + + uint32 randomNumber = scenario_rand(); + if ((randomNumber & 0xFFFF) < 0x666) { + if (randomNumber & 0x80000000) { + duck->state = DUCK_STATE_DOUBLE_DRINK; + duck->var_26 = -1; + duck_update_double_drink(duck); + } else { + duck->state = DUCK_STATE_DRINK; + duck->var_26 = -1; + duck_update_drink(duck); + } + return; + } + + int currentMonth = date_get_month(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16)); + if (currentMonth >= MONTH_SEPTEMBER && (randomNumber >> 16) < 218) { + duck->state = DUCK_STATE_FLY_AWAY; + duck_update_fly_away(duck); + return; + } + + duck_invalidate(duck); + int landZ = map_element_height(duck->x, duck->y); + int waterZ = (landZ >> 16) & 0xFFFF; + landZ &= 0xFFFF; + + if (duck->z < landZ || waterZ == 0) { + duck->state = DUCK_STATE_FLY_AWAY; + duck_update_fly_away(duck); + return; + } + + duck->z = waterZ; + randomNumber = scenario_rand(); + if ((randomNumber & 0xFFFF) <= 0xAAA) { + randomNumber >>= 16; + duck->sprite_direction = randomNumber & 0x18; + } + + int direction = duck->sprite_direction >> 3; + int x = duck->x + duck_move_offset[direction].x; + int y = duck->y + duck_move_offset[direction].y; + landZ = map_element_height(x, y); + waterZ = (landZ >> 16) & 0xFFFF; + landZ &= 0xFFFF; + + if (duck->z < landZ || duck->z != waterZ) + return; + + sprite_move(x, y, waterZ, (rct_sprite*)duck); + duck_invalidate(duck); +} + +/** + * + * rct: 0x00674357 + */ +static void duck_update_drink(rct_duck *duck) +{ + duck->var_26++; + if (duck_drink_animation[duck->var_26] == 255) { + duck->state = DUCK_STATE_SWIM; + duck->var_26 = 0; + duck_update_swim(duck); + } else { + duck_invalidate(duck); + } +} + +/** + * + * rct: 0x00674372 + */ +static void duck_update_double_drink(rct_duck *duck) +{ + duck->var_26++; + if (duck_double_drink_animation[duck->var_26] == 255) { + duck->state = DUCK_STATE_SWIM; + duck->var_26 = 0; + duck_update_swim(duck); + } else { + duck_invalidate(duck); + } +} + +/** + * + * rct: 0x0067438D + */ +static void duck_update_fly_away(rct_duck *duck) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3) + return; + + duck->var_26++; + if (duck->var_26 >= 6) + duck->var_26 = 0; + + duck_invalidate(duck); + int direction = duck->sprite_direction >> 3; + int x = duck->x + (duck_move_offset[direction].x * 2); + int y = duck->y + (duck_move_offset[direction].y * 2); + if (x < 0 || y < 0 || x >= (32 * 256) || y >= (32 * 256)) { + sprite_remove((rct_sprite*)duck); + return; + } + + int z = z = min(duck->z + 2, 496); + sprite_move(x, y, z, (rct_sprite*)duck); + duck_invalidate(duck); +} + +/** + * + * rct: 0x006E895D + */ +void duck_press(rct_duck *duck) +{ + sound_play_panned(SOUND_QUACK, 0x8001, duck->x, duck->y, duck->z); +} + +/** + * + * rct: 0x00674576 + */ +void duck_remove_all() +{ + rct_unk_sprite* sprite; + uint16 spriteIndex, nextSpriteIndex; + + for (spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_MISC, uint16); spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex) { + sprite = &(g_sprite_list[spriteIndex].unknown); + nextSpriteIndex = sprite->next; + if (sprite->misc_identifier == SPRITE_MISC_DUCK) + sprite_remove((rct_sprite*)sprite); + } +} + +static const rct_xy16 _moneyEffectMoveOffset[] = { + { 1, -1 }, + { 1, 1 }, + { -1, 1 }, + { -1, -1 } +}; + +/** + * + * rct: 0x0067351F + */ +void money_effect_create_at(money32 value, int x, int y, int z) +{ + rct_money_effect *moneyEffect; + rct_string_id stringId; + char buffer[128]; + + moneyEffect = (rct_money_effect*)create_sprite(2); + if (moneyEffect == NULL) + return; + + moneyEffect->value = value; + moneyEffect->var_14 = 64; + moneyEffect->var_09 = 20; + moneyEffect->var_15 = 30; + moneyEffect->sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite_move(x, y, z, (rct_sprite*)moneyEffect); + moneyEffect->misc_identifier = SPRITE_MISC_MONEY_EFFECT; + moneyEffect->num_movements = 0; + moneyEffect->move_delay = 0; + + stringId = 1388; + if (value < 0) { + value *= -1; + stringId = 1399; + } + format_string(buffer, stringId, &value); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + moneyEffect->offset_x = -(gfx_get_string_width(buffer) / 2); + moneyEffect->wiggle = 0; +} + +/** + * + * rct: 0x0069C5D0 + */ +void money_effect_create(money32 value) +{ + rct_window *mainWindow; + rct_viewport *mainViewport; + rct_xyz16 mapPosition; + + mapPosition.x = RCT2_GLOBAL(0x009DEA5E, uint16); + mapPosition.y = RCT2_GLOBAL(0x009DEA60, uint16); + mapPosition.z = RCT2_GLOBAL(0x009DEA62, uint16); + if (mapPosition.x == (sint16)0x8000) { + mainWindow = window_get_main(); + if (mainWindow == NULL) + return; + + mainViewport = mainWindow->viewport; + mapPosition.x = mainViewport->x + (mainViewport->width / 2); + mapPosition.y = mainViewport->y + (mainViewport->height / 2); + + int eax = mapPosition.x, ebx = mapPosition.y, ecx, edx, esi, edi, ebp; + RCT2_CALLFUNC_X(0x00688972, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + mapPosition.x = eax; + mapPosition.y = ebx; + + if (mapPosition.x == (sint16)0x8000) + return; + + mapPosition.z = map_element_height(mapPosition.x, mapPosition.y) & 0xFFFF; + } + mapPosition.z += 10; + money_effect_create_at(-value, mapPosition.x, mapPosition.y, mapPosition.z); +} + +/** + * + * rct: 0x00673232 + */ +void money_effect_update(rct_money_effect *moneyEffect) +{ + invalidate_sprite((rct_sprite*)moneyEffect); + moneyEffect->wiggle++; + if (moneyEffect->wiggle >= 22) + moneyEffect->wiggle = 0; + + moneyEffect->move_delay++; + if (moneyEffect->move_delay < 2) + return; + + moneyEffect->move_delay = 0; + int x = moneyEffect->x + _moneyEffectMoveOffset[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)].x; + int y = moneyEffect->y + _moneyEffectMoveOffset[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)].y; + int z = moneyEffect->z; + sprite_move(x, y, z, (rct_sprite*)moneyEffect); + + moneyEffect->num_movements++; + if (moneyEffect->num_movements < 55) + return; + + sprite_remove((rct_sprite*)moneyEffect); +} + +/* + * + * rct2: 0x006EC473 + */ void invalidate_sprite(rct_sprite* sprite){ if (sprite->unknown.sprite_left == (sint16)0x8000) return; @@ -75,6 +566,15 @@ void invalidate_sprite(rct_sprite* sprite){ } } +/** + * Similar to invalidate sprite... + * rct2: 0x006EC60B + */ +void sub_6EC60B(rct_sprite* sprite) +{ + RCT2_CALLPROC_X(0x006EC60B, 0, 0, 0, 0, (int)sprite, 0, 0); +} + /* * * rct2: 0x0069EB13 @@ -111,19 +611,15 @@ void reset_sprite_list(){ RCT2_GLOBAL(0x13573C8, uint16) = 0x2710; - //RCT2_CALLPROC_EBPSAFE(0x0069EBE4); reset_0x69EBE4(); } -/* - * - * rct: 0x0069EBE4 +/** + * rct2: 0x0069EBE4 * This function looks as though it sets some sort of order for sprites. * Sprites can share thier position if this is the case. */ void reset_0x69EBE4(){ - //RCT2_CALLPROC_EBPSAFE(0x0069EBE4); - //return; memset((uint16*)0xF1EF60, -1, 0x10001*2); rct_sprite* spr = g_sprite_list; @@ -143,14 +639,38 @@ void reset_0x69EBE4(){ } uint16 ax = RCT2_ADDRESS(0xF1EF60,uint16)[edi]; RCT2_ADDRESS(0xF1EF60,uint16)[edi] = spr->unknown.sprite_index; - spr->unknown.var_02 = ax; + spr->unknown.next_in_quadrant = ax; } } } +/** + * Clears all the unused sprite memory to zero. Probably so that it can be compressed better when saving. + * rct2: 0x0069EBA4 + */ +void sprite_clear_all_unused() +{ + rct_unk_sprite *sprite; + uint16 spriteIndex, nextSpriteIndex, previousSpriteIndex; + + spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16); + while (spriteIndex != SPRITE_INDEX_NULL) { + sprite = &g_sprite_list[spriteIndex].unknown; + nextSpriteIndex = sprite->next; + previousSpriteIndex = sprite->previous; + memset(sprite, 0, sizeof(rct_sprite)); + sprite->sprite_identifier = SPRITE_IDENTIFIER_NULL; + sprite->next = nextSpriteIndex; + sprite->previous = previousSpriteIndex; + sprite->linked_list_type_offset = SPRITE_LINKEDLIST_OFFSET_NULL; + sprite->sprite_index = spriteIndex; + spriteIndex = nextSpriteIndex; + } +} + /* * rct2: 0x0069EC6B -* bl: if bl & 2 > 0, the sprite ends up in the FLOATING_TEXT linked list. +* bl: if bl & 2 > 0, the sprite ends up in the MISC linked list. */ rct_sprite *create_sprite(uint8 bl) { @@ -165,7 +685,7 @@ rct_sprite *create_sprite(uint8 bl) return NULL; } - linkedListTypeOffset = SPRITE_LINKEDLIST_OFFSET_FLOATING_TEXT; + linkedListTypeOffset = SPRITE_LINKEDLIST_OFFSET_MISC; } else if (RCT2_GLOBAL(0x13573C8, uint16) <= 0) { @@ -180,14 +700,14 @@ rct_sprite *create_sprite(uint8 bl) sprite->y = SPRITE_LOCATION_NULL; sprite->z = 0; sprite->name_string_idx = 0; - sprite->var_14 = 0x10; - sprite->var_09 = 0x14; - sprite->var_15 = 0x8; - sprite->pad_0C[0] = 0x0; + sprite->sprite_width = 0x10; + sprite->sprite_height_negative = 0x14; + sprite->sprite_height_positive = 0x8; + sprite->var_0C = 0; sprite->sprite_left = SPRITE_LOCATION_NULL; - sprite->var_02 = RCT2_GLOBAL(0xF3EF60, uint16); - RCT2_GLOBAL(0xF3EF60, uint16) = sprite->sprite_index; + sprite->next_in_quadrant = RCT2_ADDRESS(0xF1EF60, uint16)[0x10000]; + RCT2_ADDRESS(0xF1EF60, uint16)[0x10000] = sprite->sprite_index; return (rct_sprite*)sprite; } @@ -244,13 +764,59 @@ void move_sprite_to_list(rct_sprite *sprite, uint8 cl) ++(RCT2_GLOBAL(0x13573C8 + cl, uint16)); } +/** + * + * rct: 0x006731CD + */ +void sprite_misc_update(rct_sprite *sprite) +{ + switch (sprite->unknown.misc_identifier) { + case SPRITE_MISC_0: + RCT2_CALLPROC_X(0x00673200, 0, 0, 0, 0, (int)sprite, 0, 0); + break; + case SPRITE_MISC_MONEY_EFFECT: + money_effect_update(&sprite->money_effect); + break; + case SPRITE_MISC_2: + RCT2_CALLPROC_X(0x00673298, 0, 0, 0, 0, (int)sprite, 0, 0); + break; + case SPRITE_MISC_3: + RCT2_CALLPROC_X(0x00673385, 0, 0, 0, 0, (int)sprite, 0, 0); + break; + case SPRITE_MISC_4: + RCT2_CALLPROC_X(0x0067339D, 0, 0, 0, 0, (int)sprite, 0, 0); + break; + case SPRITE_MISC_5: + RCT2_CALLPROC_X(0x006733B4, 0, 0, 0, 0, (int)sprite, 0, 0); + break; + case SPRITE_MISC_JUMPING_FOUNTAIN_WATER: + case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW: + jumping_fountain_update(&sprite->jumping_fountain); + break; + case SPRITE_MISC_BALLOON: + balloon_update(&sprite->balloon); + break; + case SPRITE_MISC_DUCK: + duck_update(&sprite->duck); + break; + } +} + /** * * rct: 0x00672AA4 */ -void texteffect_update_all() +void sprite_misc_update_all() { - RCT2_CALLPROC_EBPSAFE(0x00672AA4); + rct_sprite *sprite; + uint16 spriteIndex; + + spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_MISC, uint16); + while (spriteIndex != SPRITE_INDEX_NULL) { + sprite = &g_sprite_list[spriteIndex]; + spriteIndex = sprite->unknown.next; + sprite_misc_update(sprite); + } } /** @@ -260,16 +826,19 @@ void texteffect_update_all() * cx: y * dx: z */ -void sprite_move(int x, int y, int z, rct_sprite* sprite){ +void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite){ + if (x < 0 || y < 0 || x > 0x1FFF || y > 0x1FFF) + x = 0x8000; + int new_position = x; - if ((uint16)x == 0x8000)new_position = 0x10000; + if (x == (sint16)0x8000)new_position = 0x10000; else{ new_position &= 0x1FE0; new_position = (y >> 5) | (new_position << 3); } int current_position = sprite->unknown.x; - if ((uint16)sprite->unknown.x == 0x8000)current_position = 0x10000; + if (sprite->unknown.x == (sint16)0x8000)current_position = 0x10000; else{ current_position &= 0x1FE0; current_position = (sprite->unknown.y >> 5) | (current_position << 3); @@ -279,24 +848,24 @@ void sprite_move(int x, int y, int z, rct_sprite* sprite){ uint16* sprite_idx = &RCT2_ADDRESS(0xF1EF60, uint16)[current_position]; rct_sprite* sprite2 = &g_sprite_list[*sprite_idx]; while (sprite != sprite2){ - sprite_idx = &sprite2->unknown.var_02; + sprite_idx = &sprite2->unknown.next_in_quadrant; sprite2 = &g_sprite_list[*sprite_idx]; } - *sprite_idx = sprite->unknown.var_02; + *sprite_idx = sprite->unknown.next_in_quadrant; int temp_sprite_idx = RCT2_ADDRESS(0xF1EF60, uint16)[new_position]; RCT2_ADDRESS(0xF1EF60, uint16)[new_position] = sprite->unknown.sprite_index; - sprite->unknown.var_02 = temp_sprite_idx; + sprite->unknown.next_in_quadrant = temp_sprite_idx; } - if (x == 0x8000){ + if (x == (sint16)0x8000){ sprite->unknown.sprite_left = 0x8000; sprite->unknown.x = x; sprite->unknown.y = y; sprite->unknown.z = z; return; } - int new_x = x, new_y = y, start_x = x; + sint16 new_x = x, new_y = y, start_x = x; switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ case 0: new_x = new_y - new_x; @@ -316,10 +885,10 @@ void sprite_move(int x, int y, int z, rct_sprite* sprite){ break; } - sprite->unknown.sprite_left = new_x - sprite->unknown.var_14; - sprite->unknown.sprite_right = new_x + sprite->unknown.var_14; - sprite->unknown.sprite_top = new_y - sprite->unknown.var_09; - sprite->unknown.sprite_bottom = new_y + sprite->unknown.var_15; + sprite->unknown.sprite_left = new_x - sprite->unknown.sprite_width; + sprite->unknown.sprite_right = new_x + sprite->unknown.sprite_width; + sprite->unknown.sprite_top = new_y - sprite->unknown.sprite_height_negative; + sprite->unknown.sprite_bottom = new_y + sprite->unknown.sprite_height_positive; sprite->unknown.x = x; sprite->unknown.y = y; sprite->unknown.z = z; @@ -327,9 +896,9 @@ void sprite_move(int x, int y, int z, rct_sprite* sprite){ /** * - * rct2: 0x006E88D7 + * rct2: 0x0069EDB6 */ -void balloon_pop(rct_sprite *sprite) +void sprite_remove(rct_sprite *sprite) { - RCT2_CALLPROC_X(0x006E88D7, 0, 0, 0, (int)sprite, 0, 0, 0); + RCT2_CALLPROC_X(0x0069EDB6, 0, 0, 0, 0, (int)sprite, 0, 0); } \ No newline at end of file diff --git a/src/world/sprite.h b/src/world/sprite.h index 3c0cf6c28f..ed2cfe109a 100644 --- a/src/world/sprite.h +++ b/src/world/sprite.h @@ -32,33 +32,38 @@ enum SPRITE_IDENTIFIER{ SPRITE_IDENTIFIER_VEHICLE = 0, SPRITE_IDENTIFIER_PEEP = 1, - SPRITE_IDENTIFIER_FLOATING_TEXT = 2, + SPRITE_IDENTIFIER_MISC = 2, SPRITE_IDENTIFIER_LITTER = 3, + SPRITE_IDENTIFIER_NULL = 255 }; typedef enum { + SPRITE_LINKEDLIST_OFFSET_NULL = 0, SPRITE_LINKEDLIST_OFFSET_VEHICLE = 2, SPRITE_LINKEDLIST_OFFSET_PEEP = 4, - SPRITE_LINKEDLIST_OFFSET_FLOATING_TEXT = 6, - SPRITE_LINKEDLIST_OFFSET_FLOATING_LITTER = 8, + SPRITE_LINKEDLIST_OFFSET_MISC = 6, + SPRITE_LINKEDLIST_OFFSET_LITTER = 8, SPRITE_LINKEDLIST_OFFSET_UNKNOWN = 10 } SPRITE_LINKEDLIST_OFFSET; typedef struct { uint8 sprite_identifier; // 0x00 - uint8 pad_01; - uint16 var_02; + uint8 misc_identifier; // 0x01 + uint16 next_in_quadrant; // 0x02 uint16 next; // 0x04 uint16 previous; // 0x06 uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... - uint8 var_09; + // Height from center of sprite to bottom + uint8 sprite_height_negative; // 0x09 uint16 sprite_index; // 0x0A - uint8 pad_0C[2]; + uint16 var_0C; sint16 x; // 0x0E sint16 y; // 0x10 sint16 z; // 0x12 - uint8 var_14; // 0x14 - uint8 var_15; // 0x15 + // Width from center of sprite to edge + uint8 sprite_width; // 0x14 + // Height from center of sprite to top + uint8 sprite_height_positive; // 0x15 sint16 sprite_left; // 0x16 sint16 sprite_top; // 0x18 sint16 sprite_right; // 0x1A @@ -66,21 +71,139 @@ typedef struct { uint8 sprite_direction; //direction of sprite? 0x1e uint8 pad_1F[3]; // 0x1f uint16 name_string_idx; // 0x22 + uint8 pad_24[7]; + uint8 var_2B; + uint8 pad_2C[0x45]; + uint8 var_71; } rct_unk_sprite; typedef struct { - uint8 sprite_identifier; // 0x00 + uint8 sprite_identifier; // 0x00 uint8 var_01; // 0x01 - uint16 var_02; // 0x02 + uint16 next_in_quadrant; // 0x02 uint16 next; // 0x04 uint16 previous; // 0x06 uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... uint8 pad_09; uint16 sprite_index; // 0x0A - uint8 pad_0B[0x19]; + uint16 pad_0C; + sint16 x; // 0x0E + sint16 y; // 0x10 + sint16 z; // 0x12 + uint8 pad_14[0x10]; uint32 var_24; } rct_litter; +typedef struct { + uint8 sprite_identifier; // 0x00 + uint8 misc_identifier; // 0x01 + uint16 next_in_quadrant; // 0x02 + uint16 next; // 0x04 + uint16 previous; // 0x06 + uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... + uint8 var_09; // 0x09 + uint16 var_0A; + uint8 pad_0C[0x2]; + sint16 x; // 0x0E + sint16 y; // 0x10 + sint16 z; // 0x12 + uint8 var_14; // 0x14 + uint8 var_15; // 0x15 + uint8 pad_16[0xE]; + uint16 popped; // 0x24 + union { + uint16 var_26; + struct { + uint8 var_26a; + uint8 var_26b; + }; + }; + uint8 pad_28[4]; + uint8 colour; // 0x2C +} rct_balloon; + +typedef struct { + uint8 sprite_identifier; // 0x00 + uint8 misc_identifier; // 0x01 + uint16 next_in_quadrant; // 0x02 + uint16 next; // 0x04 + uint16 previous; // 0x06 + uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... + uint8 var_09; // 0x09 + uint16 var_0A; + uint8 pad_0C[0x2]; + sint16 x; // 0x0E + sint16 y; // 0x10 + sint16 z; // 0x12 + uint8 var_14; // 0x14 + uint8 var_15; // 0x15 + uint8 pad_16[0x8]; + uint8 sprite_direction; // 0x1E + uint8 pad_1F[0x7]; + uint16 var_26; + uint8 pad_28[0x8]; + sint16 target_x; // 0x30 + sint16 target_y; // 0x32 + uint8 pad_34[0x14]; + uint8 state; // 0x48 +} rct_duck; + +typedef struct { + uint8 sprite_identifier; // 0x00 + uint8 misc_identifier; // 0x01 + uint16 next_in_quadrant; // 0x02 + uint16 next; // 0x04 + uint16 previous; // 0x06 + uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... + uint8 var_09; + uint8 pad_0A[0x4]; + sint16 x; // 0x0E + sint16 y; // 0x10 + sint16 z; // 0x12 + uint8 var_14; + uint8 var_15; + uint8 pad_16[0x8]; + uint8 sprite_direction; // 0x1E + uint8 pad_1F[0x7]; + union { + uint16 var_26; + struct { + uint8 var_26a; + uint8 var_26b; + }; + }; + uint8 pad_28[0x6]; + uint8 var_2E; + uint8 flags; + sint16 target_x; // 0x30 + sint16 target_y; // 0x32 + uint8 pad_34[0x12]; + uint16 iteration; // 0x46 +} rct_jumping_fountain; + +typedef struct { + uint8 sprite_identifier; // 0x00 + uint8 misc_identifier; // 0x01 + uint16 var_02; // 0x02 + uint16 next; // 0x04 + uint16 previous; // 0x06 + uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... + uint8 var_09; + uint8 pad_0A[0x4]; + sint16 x; // 0x0E + sint16 y; // 0x10 + sint16 z; // 0x12 + uint8 var_14; + uint8 var_15; + uint8 pad_16[0xE]; + uint16 move_delay; // 0x24 + uint16 num_movements; // 0x26 + money32 value; // 0x28 + uint8 pad_2C[0x18]; + sint16 offset_x; // 0x44 + uint16 wiggle; // 0x46 +} rct_money_effect; + /** * Sprite structure. * size: 0x0100 @@ -91,19 +214,43 @@ typedef union { rct_peep peep; rct_litter litter; rct_vehicle vehicle; + rct_balloon balloon; + rct_duck duck; + rct_jumping_fountain jumping_fountain; + rct_money_effect money_effect; } rct_sprite; +enum { + SPRITE_MISC_0, + SPRITE_MISC_MONEY_EFFECT, + SPRITE_MISC_2, // (related to vehicle crash, probably crash particles) + SPRITE_MISC_3, // (related to vehicle crash, probably crash particles) + SPRITE_MISC_4, // (related to vehicle crash, probably crash particles) + SPRITE_MISC_5, // (related to vehicle crash, probably crash particles) + SPRITE_MISC_JUMPING_FOUNTAIN_WATER, + SPRITE_MISC_BALLOON, + SPRITE_MISC_DUCK, + SPRITE_MISC_JUMPING_FOUNTAIN_SNOW +}; + // rct2: 0x010E63BC extern rct_sprite* g_sprite_list; -void create_balloon(int x, int y, int z, int colour); +void create_balloon(int x, int y, int z, int colour, uint8 bl); +void balloon_press(rct_balloon *balloon); +void create_duck(int targetX, int targetY); +void duck_press(rct_duck *duck); +void duck_remove_all(); +void money_effect_create(money32 value); rct_sprite *create_sprite(uint8 bl); void reset_sprite_list(); void reset_0x69EBE4(); +void sprite_clear_all_unused(); void move_sprite_to_list(rct_sprite *sprite, uint8 cl); -void texteffect_update_all(); -void sprite_move(int x, int y, int z, rct_sprite* sprite); -void balloon_pop(rct_sprite *sprite); -void invalidate_sprite(rct_sprite* sprite); +void sprite_misc_update_all(); +void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite); +void invalidate_sprite(rct_sprite *sprite); +void sub_6EC60B(rct_sprite* sprite); +void sprite_remove(rct_sprite *sprite); #endif diff --git a/src/windows/scenery.h b/src/world/water.h similarity index 51% rename from src/windows/scenery.h rename to src/world/water.h index f9868e5709..72018c7ddc 100644 --- a/src/windows/scenery.h +++ b/src/world/water.h @@ -1,5 +1,5 @@ /***************************************************************************** -* Copyright (c) 2014 Dniel Tar +* Copyright (c) 2014 Ted John * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * This file is part of OpenRCT2. @@ -18,22 +18,17 @@ * along with this program. If not, see . *****************************************************************************/ -#ifndef _WINDOW_SCENERY_H_ -#define _WINDOW_SCENERY_H_ +#ifndef _WATER_H_ +#define _WATER_H_ -#define WINDOW_SCENERY_WIDTH 0x27A -#define WINDOW_SCENERY_HEIGHT 0x8E -#define SCENERY_BUTTON_WIDTH 66 -#define SCENERY_BUTTON_HEIGHT 80 -#define SCENERY_ENTRIES_BY_TAB 128 +#include "../common.h" -#define window_scenery_active_tab_index RCT2_GLOBAL(0x00F64EDC, uint8) -#define window_scenery_selected_scenery_by_tab RCT2_ADDRESS(0x00F64EDD, sint16) -#define window_scenery_is_build_cluster_tool_on RCT2_GLOBAL(0x00F64F1A, uint8) -#define window_scenery_is_repaint_scenery_tool_on RCT2_GLOBAL(0x00F64F19, uint8) -#define window_scenery_rotation RCT2_GLOBAL(0x00F64F05, uint8) -#define window_scenery_primary_colour RCT2_GLOBAL(0x00F64F06, uint8) -#define window_scenery_secondary_colour RCT2_GLOBAL(0x00F64F07, uint8) -#define window_scenery_tertiary_colour RCT2_GLOBAL(0x00F64F08, uint8) +typedef struct { + rct_string_id string_idx; // 0x00 + uint32 image_id; // 0x02 + uint32 var_06; + uint32 var_0A; + uint16 var_0E; +} rct_water_type; #endif \ No newline at end of file diff --git a/test.bat b/test.bat new file mode 100644 index 0000000000..59c0adf8e0 --- /dev/null +++ b/test.bat @@ -0,0 +1,2 @@ +msbuild .\projects\openrct2.sln "/p:Configuration=Release with Tests" /p:Platform=Win32 +.\build\Release\openrct2.exe test \ No newline at end of file diff --git a/test/management/finance_test.c b/test/management/finance_test.c new file mode 100644 index 0000000000..0772dfb0ff --- /dev/null +++ b/test/management/finance_test.c @@ -0,0 +1,60 @@ +/***************************************************************************** +* Copyright (c) 2015 Marco Costa +* 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 "../../src/addresses.h" +#include "../../src/management/finance.h" +#include "../../src/openrct2.h" +#include "../../src/scenario.h" + +#include "finance_test.h" + +void test_finance_setup(CuTest* tc) { + test_load_scenario(tc, "Build your own Six Flags Park.SC6"); +} + +void test_finance_loan_increase(CuTest* tc) { + money32 initialCash = finance_get_current_cash(); + money32 initialLoan = finance_get_current_loan(); + + money32 newLoan = finance_get_maximum_loan(); + finance_set_loan(newLoan); + + money32 actual = finance_get_current_loan(); + CuAssertIntEquals(tc, newLoan, actual); + + money32 actualCash = finance_get_current_cash(); + CuAssertIntEquals(tc, initialCash + newLoan - initialLoan, actualCash); +} + +void test_finance_loan_pay_back(CuTest* tc) { + money32 initialCash = finance_get_current_cash(); + money32 initialLoan = finance_get_current_loan(); + + money32 newLoan = MONEY(0, 00); + finance_set_loan(newLoan); + + money32 actual = finance_get_current_loan(); + CuAssertIntEquals(tc, newLoan, actual); + + money32 actualCash = finance_get_current_cash(); + CuAssertIntEquals(tc, MONEY(0, 00), actualCash); +} + + diff --git a/test/management/finance_test.h b/test/management/finance_test.h new file mode 100644 index 0000000000..700a79ebc9 --- /dev/null +++ b/test/management/finance_test.h @@ -0,0 +1,30 @@ +/***************************************************************************** +* Copyright (c) 2015 Marco Costa +* 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 _FINANCE_TEST_H_ +#define _FINANCE_TEST_H_ + +#include "../tests.h" + +void test_finance_setup(CuTest* tc); +void test_finance_loan_increase(CuTest* tc); +void test_finance_loan_pay_back(CuTest* tc); + +#endif \ No newline at end of file diff --git a/test/ride/ride_ratings_test.c b/test/ride/ride_ratings_test.c new file mode 100644 index 0000000000..929396f6ca --- /dev/null +++ b/test/ride/ride_ratings_test.c @@ -0,0 +1,38 @@ +#include "../../src/ride/ride_ratings.h" +#include "../../src/localisation/localisation.h" + +#include "ride_ratings_test.h" + +void test_ride_ratings_setup(CuTest* tc) { + test_load_scenario(tc, "Six Flags Magic Mountain.SC6"); +} + +void test_ride_ratings(CuTest* tc) { + int i; + rct_ride *ride; + rating_tuple *rideRatings = malloc(256 * sizeof(rating_tuple)); + char rideName[256]; + char buffer[256]; + + // Store original ride ratings + FOR_ALL_RIDES(i, ride) + rideRatings[i] = ride->ratings; + + // Update all the ride ratings + // TODO use a better function that can just be called once for each ride + for (int i = 0; i < MAX_RIDES * 10; i++) + ride_ratings_update_all(); + + FOR_ALL_RIDES(i, ride) { + format_string(rideName, ride->name, &ride->name_arguments); + + sprintf(buffer, "[%s.excitement]", rideName); + CuAssertIntEquals_Msg(tc, buffer, rideRatings[i].excitement, ride->excitement); + sprintf(buffer, "[%s.intensity]", rideName); + CuAssertIntEquals_Msg(tc, buffer, rideRatings[i].intensity, ride->intensity); + sprintf(buffer, "[%s.nausea]", rideName); + CuAssertIntEquals_Msg(tc, buffer, rideRatings[i].nausea, ride->nausea); + } + + free(rideRatings); +} \ No newline at end of file diff --git a/test/ride/ride_ratings_test.h b/test/ride/ride_ratings_test.h new file mode 100644 index 0000000000..43526ef500 --- /dev/null +++ b/test/ride/ride_ratings_test.h @@ -0,0 +1,9 @@ +#ifndef _RIDE_RATINGS_TEST_H_ +#define _RIDE_RATINGS_TEST_H_ + +#include "../tests.h" + +void test_ride_ratings_setup(CuTest* tc); +void test_ride_ratings(CuTest* tc); + +#endif \ No newline at end of file diff --git a/test/tests.c b/test/tests.c new file mode 100644 index 0000000000..487306343d --- /dev/null +++ b/test/tests.c @@ -0,0 +1,76 @@ +/***************************************************************************** +* Copyright (c) 2015 Marco Costa +* 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 "../src/openrct2.h" +#include "management/finance_test.h" +#include "ride/ride_ratings_test.h" + +int cmdline_for_test(const char **argv, int argc) +{ + // NOTE Currently all tests are running in a OpenRCT2 setup frame. Tests for the initialisation and disposing should be + // separate and independent. + + int numFailedTests; + + gOpenRCT2Headless = true; + if (openrct2_initialise()) { + numFailedTests = run_all_tests(); + + openrct2_dispose(); + } + return numFailedTests > 0 ? -1 : 1; +} + +CuSuite* new_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + + // Test Finance + SUITE_ADD_TEST(suite, test_finance_setup); + SUITE_ADD_TEST(suite, test_finance_loan_increase); + SUITE_ADD_TEST(suite, test_finance_loan_pay_back); + + // Test Ride + SUITE_ADD_TEST(suite, test_ride_ratings_setup); + SUITE_ADD_TEST(suite, test_ride_ratings); + + // Future Tests: + // Test X + // SUITE_ADD_TEST(suite, test_X_setup); + // SUITE_ADD_TEST(suite, test_X_Y); + // SUITE_ADD_TEST(suite, test_X_Z); + + return suite; +} + +int run_all_tests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + CuSuiteAddSuite(suite, new_suite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("Test results:\n%s\n", output->buffer); + + return suite->failCount; +} diff --git a/test/tests.h b/test/tests.h new file mode 100644 index 0000000000..10f94b39ed --- /dev/null +++ b/test/tests.h @@ -0,0 +1,43 @@ +/***************************************************************************** +* Copyright (c) 2015 Marco Costa +* 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 _TESTS_H_ +#define _TESTS_H_ + +#include +#include +#include "../src/common.h" + +int cmdline_for_test(const char **argv, int argc); +int run_all_tests(); + +// Test utilities + +#include "../src/scenario.h" + +static void test_load_scenario(CuTest* tc, const char* file_name) { + const rct_scenario_basic* scenario = get_scenario_by_filename(file_name); + if (scenario == NULL) { + CuFail(tc, "Could not load scenario"); + } + scenario_load_and_play(scenario); +} + +#endif \ No newline at end of file